callbale只是一个接口,用来处理执行一个线程后可以获取到线程的返回值,这个是主要的用途
public interface Callable {
V call() throws Exception;
}
从上面看这个接口非常的简单,仅仅是执行一个返回,然后有个返回值,这个在线程中的实现原理是什么样的?返回值是怎么处理的?
其实就是让某个线程中有个callable接口的实例,然后在调用call这个方法,将返回值储存起来,在某个时候去调用。由于为了方便我们,
java的类库中已经很好的实现了这个逻辑,那么我们就来聊聊。
V get() :获取异步执行的结果,如果没有结果可用,此方法会阻塞直到异步计算完成。
V get(Long timeout , TimeUnit unit) :获取异步执行结果,如果没有结果可用,此方法会阻塞,但是会有时间限制,如果阻塞时间超过设定的timeout时间,该方法将抛出异常。
boolean isDone() :如果任务执行结束,无论是正常结束或是中途取消还是发生异常,都返回true。
boolean isCanceller() :如果任务完成前被取消,则返回true。
boolean cancel(boolean mayInterruptRunning) :如果任务还没开始,执行cancel(…)方法将返回false;如果任务已经启动,执行cancel(true)方法将以中断执行此任务线程的方式来试图停止任务,如果停止成功,返回true;当任务已经启动,执行cancel(false)方法将不会对正在执行的任务线程产生影响(让线程正常执行到完成),此时返回false;当任务已经完成,执行cancel(…)方法将返回false。mayInterruptRunning参数表示是否中断执行中的线程。
通过方法分析我们也知道实际上Future提供了3种功能:
(1)能够中断执行中的任务
(2)判断任务是否执行完成
(3)获取任务执行完成后额结果。
public interface Future {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
Future接口的实现类实现了Runable和Future的方法,可以看做为一个Runable可以直接扔到线程池中去执行,主要看看FutureTask的实现类的成员变量和run方法的实现
//状态的转换
/* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
private volatile int state;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
private static final int EXCEPTIONAL = 3;
private static final int CANCELLED = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED = 6;
/** The underlying callable; nulled out after running */
private Callable callable;//执行callable的子类的实例
/** The result to return or exception to throw from get() */
//返回值
private Object outcome; // non-volatile, protected by state reads/writes
/** The thread running the callable; CASed during run() */
//当前执行的线程的引用,用来取消或者中断当前的线程
private volatile Thread runner;
//调用get的堆栈线程
/** Treiber stack of waiting threads */
private volatile WaitNode waiters;
public FutureTask(Callable callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
//执行Runable 伪造一个返回值,就是你传递进去的...
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
run方法是重点的代码
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();//保存结果
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);//如果有异常保存下来,get的时候在扔给你....
}
if (ran)
set(result);//这里执行完了会调用finishCompletion,会将所有的阻塞的返回!
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
package Thread;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
/**
* descrption: 实现Callable接口将线程执行后的结果返回
* authohr: wangji
* date: 2017-09-01 15:21
*/
@Slf4j
public class ComputeTask implements Callable<Integer> {
private Integer result = 0;
private String taskName = "";
public ComputeTask(Integer iniResult, String taskName){
result = iniResult;
this.taskName = taskName;
}
public Integer call() throws Exception {
return todoWork();
}
public Integer todoWork() {
log.info("子线程计算任务: "+taskName+" 开始执行!");
for (int i = 0; i < 100; i++) {
result =i+result;
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
log.error("线程被中断",e);
}
log.info("子线程计算任务: "+taskName+" 执行完成! 结果:"+result);
return result;
}
public String getTaskName(){
return this.taskName;
}
}
package Thread;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* descrption: 测试执行线程的返回值
* authohr: wangji
* date: 2017-09-01 15:27
*/
@Slf4j
public class CallableTest {
public static void main(String[] args) {
//1. create a thread pool
ExecutorService executorService = Executors.newFixedThreadPool(5);
//2 create a list of Callable
List> returnFutureList = new ArrayList>();
for(int i=0;i<20;i++){
//ComputeTask implement callbale interface
ComputeTask callableItem = new ComputeTask(30+i,"work"+i);
Future future = executorService.submit(callableItem);
returnFutureList.add(future);
}
log.info("提交完了任务,可以把其他的事情做完了,再来轮询获取线程返回的结果的信息");
for(int i=0;i future =null;
try {
future = returnFutureList.get(i);
//依次阻塞一直等待获取到结果的信息
Integer taskReturnValue = future.get();
} catch (InterruptedException e) {
log.error("当前线程中断",e);
Thread.currentThread().interrupt();//重新声明线程中断了
if(future !=null){
future.cancel(true);
}
} catch (ExecutionException e) {
log.error("执行线程异常",e);
if(future !=null){
future.cancel(true);
}
}
}
}
}
2017-09-01 15:52:23,799 INFO [ComputeTask.java:25] : 子线程计算任务: work0 开始执行!
2017-09-01 15:52:23,799 INFO [CallableTest.java:31] : 提交完了任务,可以把其他的事情做完了,再来轮询获取线程返回的结果的信息
2017-09-01 15:52:23,799 INFO [ComputeTask.java:25] : 子线程计算任务: work4 开始执行!
2017-09-01 15:52:23,799 INFO [ComputeTask.java:25] : 子线程计算任务: work3 开始执行!
2017-09-01 15:52:23,799 INFO [ComputeTask.java:25] : 子线程计算任务: work2 开始执行!
2017-09-01 15:52:23,799 INFO [ComputeTask.java:25] : 子线程计算任务: work1 开始执行!
2017-09-01 15:52:28,801 INFO [ComputeTask.java:34] : 子线程计算任务: work0 执行完成! 结果:4980
2017-09-01 15:52:28,802 INFO [ComputeTask.java:25] : 子线程计算任务: work5 开始执行!
2017-09-01 15:52:28,803 INFO [ComputeTask.java:34] : 子线程计算任务: work4 执行完成! 结果:4984
2017-09-01 15:52:28,803 INFO [ComputeTask.java:34] : 子线程计算任务: work1 执行完成! 结果:4981
2017-09-01 15:52:28,803 INFO [ComputeTask.java:34] : 子线程计算任务: work3 执行完成! 结果:4983
2017-09-01 15:52:28,803 INFO [ComputeTask.java:34] : 子线程计算任务: work2 执行完成! 结果:4982
2017-09-01 15:52:28,804 INFO [ComputeTask.java:25] : 子线程计算任务: work8 开始执行!
2017-09-01 15:52:28,804 INFO [ComputeTask.java:25] : 子线程计算任务: work7 开始执行!
2017-09-01 15:52:28,803 INFO [ComputeTask.java:25] : 子线程计算任务: work6 开始执行!
2017-09-01 15:52:28,805 INFO [ComputeTask.java:25] : 子线程计算任务: work9 开始执行!
2017-09-01 15:52:33,803 INFO [ComputeTask.java:34] : 子线程计算任务: work5 执行完成! 结果:4985
2017-09-01 15:52:33,804 INFO [ComputeTask.java:25] : 子线程计算任务: work10 开始执行!
2017-09-01 15:52:33,807 INFO [ComputeTask.java:34] : 子线程计算任务: work8 执行完成! 结果:4988
2017-09-01 15:52:33,807 INFO [ComputeTask.java:34] : 子线程计算任务: work7 执行完成! 结果:4987
2017-09-01 15:52:33,808 INFO [ComputeTask.java:34] : 子线程计算任务: work6 执行完成! 结果:4986
2017-09-01 15:52:33,807 INFO [ComputeTask.java:25] : 子线程计算任务: work11 开始执行!
2017-09-01 15:52:33,808 INFO [ComputeTask.java:25] : 子线程计算任务: work13 开始执行!
2017-09-01 15:52:33,808 INFO [ComputeTask.java:25] : 子线程计算任务: work12 开始执行!
2017-09-01 15:52:33,812 INFO [ComputeTask.java:34] : 子线程计算任务: work9 执行完成! 结果:4989
2017-09-01 15:52:33,812 INFO [ComputeTask.java:25] : 子线程计算任务: work14 开始执行!
2017-09-01 15:52:38,804 INFO [ComputeTask.java:34] : 子线程计算任务: work10 执行完成! 结果:4990
2017-09-01 15:52:38,805 INFO [ComputeTask.java:25] : 子线程计算任务: work15 开始执行!
2017-09-01 15:52:38,809 INFO [ComputeTask.java:34] : 子线程计算任务: work13 执行完成! 结果:4993
2017-09-01 15:52:38,809 INFO [ComputeTask.java:34] : 子线程计算任务: work11 执行完成! 结果:4991
2017-09-01 15:52:38,810 INFO [ComputeTask.java:34] : 子线程计算任务: work12 执行完成! 结果:4992
2017-09-01 15:52:38,809 INFO [ComputeTask.java:25] : 子线程计算任务: work16 开始执行!
2017-09-01 15:52:38,810 INFO [ComputeTask.java:25] : 子线程计算任务: work18 开始执行!
2017-09-01 15:52:38,810 INFO [ComputeTask.java:25] : 子线程计算任务: work17 开始执行!
2017-09-01 15:52:38,813 INFO [ComputeTask.java:34] : 子线程计算任务: work14 执行完成! 结果:4994
2017-09-01 15:52:38,813 INFO [ComputeTask.java:25] : 子线程计算任务: work19 开始执行!
2017-09-01 15:52:43,806 INFO [ComputeTask.java:34] : 子线程计算任务: work15 执行完成! 结果:4995
2017-09-01 15:52:43,812 INFO [ComputeTask.java:34] : 子线程计算任务: work16 执行完成! 结果:4996
2017-09-01 15:52:43,813 INFO [ComputeTask.java:34] : 子线程计算任务: work17 执行完成! 结果:4997
2017-09-01 15:52:43,813 INFO [ComputeTask.java:34] : 子线程计算任务: work18 执行完成! 结果:4998
2017-09-01 15:52:43,815 INFO [ComputeTask.java:34] : 子线程计算任务: work19 执行完成! 结果:4999
实现原理:主要是线程池实现了这几个接口,间接的使用了FutureTask(FutureTaks 实现了Runable所以可以直接调用void execute(Runnable command);)
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future> submit(Runnable task);
看线程池的内部的实现
//AbstractExecutorService
public Future submit(Callable task) {
if (task == null) throw new NullPointerException();
RunnableFuture ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
看这个下面的看懂了吧!new 了一个FutureTask,ftask本身实现了Runable所以就很直接了,运行线程的结果,就保存在了FutureTask的实例中啦!
//AbstractExecutorService
protected RunnableFuture newTaskFor(Callable callable) {
return new FutureTask(callable);
}
上面这个测试的缺陷非常的明显,需要一个个的执行等待,即使先执行完成的也不能首先获取得到他的返回的值,有一种解决方案
ExecutorCompletionService,将Executor和BlockingQueue功能融合在一起
[http://blog.csdn.net/lmj623565791/article/details/27250059](带返回结果的批量任务执行 CompletionService ExecutorService.invokeAll)
[http://blog.csdn.net/u010185262/article/details/55255452](FutureTask 讲解的不错)
http://huangyunbin.iteye.com/blog/1942369
http://www.cnblogs.com/Mainz/p/3546347.html