Runnable,Callable,Future,FutureTask的区别:
参考:https://baijiahao.baidu.com/s?id=1631326488605078999&wfr=spider&for=pc
一般创建线程的方法:继承Thread,实现Runnable
这两种都没有返回值,一般需要用到Handler去发送结果然后处理;
在这两种传统方法中,推荐Runnable,因为Thread只能继承,Java只有单继承,而Runnable是通过接口;
并且在线程池中,Runnable可以直接传入其中使用;如
private ExecutorService executorService = Executors.newFixedThreadPool(5);
executorService.execute(new Runnable() {
@Override
public void run() {
//.....
}
});
在java1.5之后有了Callable和Future,这两种可以提供线程返回的结果;
1.Runnable:
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
//...
}
});
thread.start();
附带:thread的start和run有什么区别?
start是开启新线程,这时线程处于就绪状态,一旦得到cpu时间片,边开始运行;
run:只是类的一个普通方法而已,如果直接调用run,程序中依然只有主线程;
2.Callable
和Runnable的区别是有返回结果,且可以抛出异常;一般是配合线程池调用;
Callable callable = new Callable<String>() {
@Override
public String call() throws Exception {
return "result";
}
};
ExecutorService executorService = Executors.newFixedThreadPool(5);
Future future = executorService.submit(callable);
try {
System.out.println(future.get());
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
3.Future
Future也是一个接口,它可以对具体的Runnable或者Callable任务进行取消,获取运行结果;
如果是Runnable的话获取的结果为null,get会阻塞当前调用get的线程,直到返回结果或者超时才会唤醒当前线程;
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning); //取消任务
boolean isCancelled(); //判断是否已取消
boolean isDone(); //判断任务是否已结束
V get() throws InterruptedException, ExecutionException; //获取任务执行结果
V get(long timeout, TimeUnit unit) //加超时时间
throws InterruptedException, ExecutionException, TimeoutException;
}
4.FutureTask
相比与Future的好处是Future是一个接口,不能直接new;
而FutureTask是一个class,实现了RunnableFuture接口;
RunnableFuture 又实现了Runnable和Future两个接口;
因此FutureTask既可以作为Runnable被线程执行,又有着Future的特性(获取结果/抛异常);
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
使用
FutureTask futureTask = new FutureTask(callable);
//由于futureTask自带返回结果,所以可以不用submit方法
executorService.execute(futureTask);
try {
System.out.println(futureTask.get());
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
5.submit方法
疑问:为什么使用submit方法而不用execute方法?
答:需要返回结果就要用submit;
submit方法实现
//传入的是Runnable,将Runnable转化为FutureTask实例
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
//传入的是Callable,将Runnable转化为FutureTask实例
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
//FutureTask是RunnableFuture接口的实现类
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
所以submit之所以可以返回结果,其实就是使用了FutureTask
submit就是将传入的Runnable或者Callable转化为RunnableFuture,然后调用execute
因此如果一开始就是FutureTask,则可以直接使用execute.