1.Runnable

Runnable是个接口,使用很简单:
1. 实现该接口并重写run方法
2. 利用该类的对象创建线程
3. 线程启动时就会自动调用该对象的run方法
通常在开发中结合ExecutorService使用,将任务的提交与任务的执行解耦开,同时也能更好地利用Executor提供的各种特性
ExecutorService executor = Executors.newCachedThreadPool();
executor.submit(new Runnable() {
public void run() {
//TODO
}
});
executor.shutdown();
相对于继承Thread来创建线程方式,使用Runnable可以让你的实现类同时实现多个接口,而相对于Callable及Future,Runnable方法并不返回任务执行结果且不能抛出异常
 
2.Callable
与Runnable不同的是,Callable是个泛型参数化接口,并能返回线程的执行结果,且能在无法正常计算时抛出异常
public interface Callable<V> {
V call() throws Exception;
}
1. Callable并不像Runnable那样通过Thread的start方法就能启动实现类的run方法,所以它通常利用ExecutorService的submit方法去启动call方法自执行任务,而ExecutorService的submit又返回一个Future类型的结果,因此Callable通常也与Future一起使用
 ExecutorService pool = Executors.newCachedThreadPool();
Future<String> future = pool.submit(new Callable{
public void call(){
//TODO
}
});
或者利用FutureTask封装Callable再由Thread去启动(少用)
 FutureTask<String> task = new FutureTask(new Callable{
public void call(){
//TODO
}
});
Thead thread = new Thread(task);
thread.start();
2. 通过Executors.callbale(Runnable task,T result)可以执行Runnable并返回"结果",但是这个结果并不是Runnable的执行结果(Runnable的run方法是void类型),而是执行者预定义的结果,这点可以从其实现原理RunnableAdpter源码看出
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);//通过RunnableAdapter实现
} static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result; //将传入的结果的直接返回
}
}
Runnable与Callable不同点:
1. Runnable不返回任务执行结果,Callable可返回任务执行结果
2. Callable在任务无法计算结果时抛出异常,而Runnable不能
3. Runnable任务可直接由Thread的start方法或ExecutorService的submit方法去执行
 
3.Future
Future保存异步计算的结果,可以在我们执行任务时去做其他工作,并提供了以下几个方法
* cancel(boolean mayInterruptIfRunning):试图取消执行的任务,参数为true时直接中断正在执行的任务,否则直到当前任务执行完成,成功取消后返回true,否则返回false
* isCancel():判断任务是否在正常执行完前被取消的,如果是则返回true
* isDone():判断任务是否已完成
* get():等待计算结果的返回,如果计算被取消了则抛出
* get(long timeout,TimeUtil unit):设定计算结果的返回时间,如果在规定时间内没有返回计算结果则抛出TimeOutException
使用Future的好处:
1. 获取任务的结果,判断任务是否完成,中断任务
1. Future的get方法很好的替代的了Thread.join或Thread,join(long millis)
2. Future的get方法可以判断程序代码(任务)的执行是否超时,如:
 try{
future.get(60,TimeUtil.SECOND);
}catch(TimeoutException timeout){
log4j.log("任务越野,将被取消!!");
future.cancel();
}
4.FutureTask
FutureTask实现了RunnableFuture接口,提供了即可以使用Runnable来执行任务,又可以使用Future执行任务并取得结果的构造器,所以可以利用FutureTask去封装Runnable或Callable对象,之后再submit任务
 FutureTask(Callable<V> callable)
FutureTask(Runnable runnable, V result)

5.应用

查找包含某关键字的文件个数:每个文件启动一个线程去查找关键字
public class FileSearchTask {
public static void main(String[] args) throws ExecutionException, InterruptedException {
String path = args[0];
String keyword = args[1];
int c = 0;
File[] files = new File(path).listFiles();
ArrayList<Future<Integer>> rs = new ArrayList<>();
for(File file: files){ //每个文件启动一个task去查找
MatchCount count = new MatchCount();
count.file = file;
count.keyword = keyword;
FutureTask<Integer> task = new FutureTask(count);
rs.add(task); //将任务返回的结果添加到集合中
Thread thread = new Thread(task);
thread.start();
} for(Future<Integer> f: rs){
c += f.get(); //迭代返回结果并累加
}
System.out.println("包含关键字的总文件数为:" + c);
}
} class MatchCount implements Callable<Integer>{
public File file;
public String keyword;
private Integer count = 0; public Integer call() throws Exception { //call封装线程所需做的任务
if(search(file))
count ++;
return count;
} public boolean search(File file){
boolean founded = false;
try(Scanner scanner = new Scanner(new FileInputStream(file))){
while(!founded && scanner.hasNextLine()){
if (scanner.nextLine().contains(keyword))
founded = true;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return founded;
}
}
 Java并发编程相关的例子:https://github.com/MOBIN-F/Thread
 

java并发编程--Runnable Callable及Future的更多相关文章

  1. Java并发编程:Callable、Future和FutureTask

    作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...

  2. (转)Java并发编程:Callable、Future和FutureTask

    Java并发编程:Callable.Future和FutureTask 在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一 ...

  3. Java并发编程:Callable、Future和FutureTask(转)

    Java并发编程:Callable.Future和FutureTask 在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一 ...

  4. 15、Java并发编程:Callable、Future和FutureTask

    Java并发编程:Callable.Future和FutureTask 在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Runnable接口. 这2种方式都有一 ...

  5. 007 Java并发编程:Callable、Future和FutureTask

    原文https://www.cnblogs.com/dolphin0520/p/3949310.html Java并发编程:Callable.Future和FutureTask 在前面的文章中我们讲述 ...

  6. Java 并发编程:Callable和Future

    项目中经常有些任务需要异步(提交到线程池中)去执行,而主线程往往需要知道异步执行产生的结果,这时我们要怎么做呢?用runnable是无法实现的,我们需要用callable实现. import java ...

  7. Java并发编程:Callable、Future和FutureTask的实现

    启动线程执行任务,如果需要在任务执行完毕之后得到任务执行结果,可以使用从Java 1.5开始提供的Callable和Future 下面就分析一下Callable.Future以及FutureTask的 ...

  8. [转载] Java并发编程:Callable、Future和FutureTask

    转载自http://www.cnblogs.com/dolphin0520/p/3949310.html 在前面的文章中我们讲述了创建线程的2种方式,一种是直接继承Thread,另外一种就是实现Run ...

  9. 【Java并发编程】Callable、Future和FutureTask的实现

    启动线程执行任务,如果需要在任务执行完毕之后得到任务执行结果,可以使用从Java 1.5开始提供的Callable和Future 下面就分析一下Callable.Future以及FutureTask的 ...

随机推荐

  1. 画年利率 画图 自定义 View

    使用 SlbSyView slbView; slbView = (SlbSyView) findViewById(R.id.slbView); slbView.setHeights(new float ...

  2. return;,return false,return true----------浅析

    作为新手,一直没注意他们的区别,今天特意在网上搜了搜. 1: retuen; 无返回值,表示终止函数往下执行 2: return true; a.返回 bool值 真 b.提交表单 针对<but ...

  3. MD5加密运算

    //MD5 对字符串的加密 -(void)demo1 { NSString *str = @"love"; //对字符串进行MD5加密 str = str.md5String; N ...

  4. aps.net 用ajax 读取服务端值

      1.Default.aspx 页面内容 实例一: <%@ Page Language="C#" AutoEventWireup="true" Code ...

  5. JavaWeb学习笔记之JSP(二)

    1.1.  JSP的指令: 1.   什么是JSP 指令? JSP 指令: JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出, 而只是告诉引擎如何处理JSP页面中的 ...

  6. 使用2to3转换python代码

    如果要把python2编译器下的代码转换升级到python3编译器,可以使用python自带的 2to3工具进行转化: windows下转化: doc 命令窗口: >> python  C ...

  7. Ubuntu 13.04 用Sublime Text 2 编译运行 JAVA

    将下面的代码粘贴到JavaC.sublime-build中: { "cmd": ["javac \"$file_name\" && j ...

  8. SQL Server 触发器(转)

    触发器是一种特殊类型的存储过程,它不同于之前的我们介绍的存储过程.触发器主要是通过事件进行触发被自动调用执行的.而存储过程可以通过存储过程的名称被调用. Ø 什么是触发器 触发器对表进行插入.更新.删 ...

  9. Pycharm在创建py文件时,如何自动添加文件头注释(类似于钩子特性)?

    在每次新建一个py文件的时候 1 如何自动添加/usr/bin/env python2 自动添加 coding=utf8 操作方法: File->settings->Editor-> ...

  10. TagHelper

    TagHelper是怎么实现的   众所周知,在asp.net core中编写Razor视图的时候,用了一种新的写法--TagHelper 那这个TagHelper是怎么回事呢? 首先来看看TagHe ...