java线程中的Runnable,Callable,Future,FutureTask

前言,在java线程中最常见的是Thread 和Runnable,很少见到或者用到callable等类。但是,你接触过android源码就会经常看到这些类,比如AsyncTask的源码在execute方法源码可以看到了这些类。在面试时也有可能会问到两者的区别,所以现在容许鄙人来介绍一下java中这些类的用法。

Runnable

Runnable一个接口类,包括一个run的接口方法:通常我们会自定义一个类去实现Runnable,这时候还可以实现其他接口方法,如果类要是继承Thread就不能再继承其他类了。

1
2
3
public interface Runnable{
public abstract void run();
}

Runnable 通常配合Thread使用,在run方法里面写耗时的操作:

1
2
3
4
5
new Thread(new Runnable(){
public void run(){
//
}
}).start();

Callable

Callable是一个泛型接口,要比Runnable强些 ,因为接口方法call有返回值,并且返回值是传入的泛型类型,还能call的过程中抛出异常。

1
2
3
public interface Callable<V>{
V call() throws Exception;
}

示例要配合Future或者FutureTask来执行。

Future

Future是一个泛型接口类,是Runnable和Callable的调度容器,就是对Runnable和Callable的结果进行操作,比如:

  1. isCancelled()取消操作,call方法任务完成前取消,返回true。
  2. isDone()判断是否操作完成,是则返回true。
  3. get()获取操作结果,会导致程序阻塞,必须等到子线程结束才会得到返回值。
  4. get(long timeout TimeUnit unit)在某时间后获取操作结果,如果在规定时间内获取不到返回值将会抛出超时异常)
1
2
3
4
5
6
7
public interface Future<V>{
boolean isCancelled();
boolean isDone();
V get() throws InterputeredException,ExecutionExeception;
V get(long timeout ,TimeUnit unit)throws InterputeredException,ExecutionExeception,TimeoutExeception;

}

比如

1
2
3
4
5
6
7
8
9
ExecutorService threadPool=Executors.newSingleThreadExecutor();
Future future=threadPool.submit(new Callable<String>(){
public String call()throws Exception{
return "result";
}

});

Futurn.get();//返回操作结果

FutureTask

FutureTask类同时实现了Runnable和Future 两个接口,具有了两个接口的属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class FutureTask<V> implements RunnableFuture<V>{
public FutureTask(Callable<V> callable){
this.callable=callable;
...
}
public FutureTask(Runnable runnable,V result){
this.callable=Executors.callable(runnable,result);
...
}
boolean isCancelled();
boolean isDone();
V get() throws InterputeredException,ExecutionExeception;
V get(long timeout ,TimeUnit unit)throws InterputeredException,ExecutionExeception,TimeoutExeception;
}
public interface RunnableFuture<V> implements Runnable,Callable<V>{
void run();
}

这里的FutureTask间接实现了两个接口,在FutureTask的构造方法传入Callable或者是Runnable都会转为callable,runnable通过runnableadapter转为callable。同时FutureTask还具备Future的所有方法。

举个例子

1
2
3
4
5
6
7
8
9
Callable<Integer> callable=new Callable<Integer>(){
public Ingeter call() throws Exception{
return 100;
}
};
FutureTask<Integer> task=new FutureTask<Integer>(callable);
new Thread(task).start();

task.get();//当然要先启动线程才能得到结果;

这里的callable当成runnable用了。

总结

  1. Callable比Runnable高级能返回结果值和抛出异常。

  2. 可以有上述例子看到Callable来产生结果,Futuretask来获取结果。

  3. 在获取结果期间还可以控制是否取消thread 判断thread是否完成。