1.FutureTask 用于获取线程run方法的返回值。下面看个实例代码
static class MyTask implements Callable<String> {
@Override
public String call() throws Exception {
return "xxx";
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
MyTask myTask = new MyTask();
FutureTask<String> futureTask = new FutureTask<>(myTask);
new Thread(futureTask).start();
//让run方法先执行完
Thread.sleep(1000);
System.err.println(futureTask.get());
}
}
2.代码调式
首先进入FutureTask的构造函数
然后 执行 new Thread(futureTask).start(); 会回调futureTask的run方法。
到此我们的call业务以及执行完成,然后进入set方法,将执行的业务结果值传入set函数。
上面代码利用cas操作将全局变量state改成NORMAL状态(2),并且将业务执行结果,缓存在全局变量outcome上。
将下来执行finishCompletion函数
相当于什么都没做,done函数是空的。
到此我们的线程执行完毕!进入我们的futureTask.get() 得到结果。
直接执行report函数
这是第一种情况,我们接下来换下客户端代码
static class MyTask implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(100);
return "xxx";
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
MyTask myTask = new MyTask();
FutureTask<String> futureTask = new FutureTask<>(myTask);
new Thread(futureTask).start();
//get会阻塞,直到futureTask 的run方法执行完成,才醒来
System.err.println(futureTask.get());
}
先执行 futureTask.get() 代码
进入awaitDone方法
第一次循环构造了WaitNode节点。
第二次循环会得到下面的数据结构:
第三次循环,我们记记住上面的数据结构
到此线程进行阻塞等待。
接下来改子线程执行FutureTask的run方法了。
上面这段代码就是取正在等待的node节点,然后将其唤醒。
接下来主线程唤醒。
然后执行导出,结果就返回出去了。