Java多线程Callable源码详解
Callable 与 Runnable 对比
利用线程对1~100求和,并返回sum值输出在控制台中
// 使用Runnable创建线程
public class Runnable_Callable {
public int sum = 0;
public static void main(String[] args) throws InterruptedException {
Runnable_Callable rc = new Runnable_Callable();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
rc.sum = sum;
}
});
t1.start();
t1.join();
System.out.println(rc.sum);
}
}
可以看到,要想返回sum值,非常麻烦,所以,利用Callable可以快速的获得返回值.
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
int sum = 0;
for (int i = 0; i <= 100; i++) {
sum += i;
}
return sum;
}
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread t2 = new Thread(futureTask);
t2.start();
Integer sum = futureTask.get();
System.out.println(sum);
通过Callable,可以将计算的值直接返回出来.
下面源码分析!!
Callable 源码分析
几个问题:
Callable
没有run
,为什么可以用Callable创建一个线程.- 为什么
Callable
有返回值 FutureTask
起到了什么作用
1.观察Thread构造方法
观察发现,Thread并没有参数为Callable
类型的参数,所以利用FutureTask
包装,而FutureTask
实现了RunnableFuture<V>
接口,RunnableFuture<V>
又实现了Runnable
接口.所以,可以传入FutureTask
作为Thread
的参数.
2.对于FutureTask
类
则可以接收一个Callable
类的对象
3.当线程启动时,会调用FutureTask
的run()
方法启动线程,
此处有解锁步骤,猜测获取返回值时会存在加锁
get()方法
总结:当
Thread
调用start()
方法时,自动调用FutureTask
的run()
方法,由run()
方法调用call()
方法,并将返回值记录下来保存在outcome
全局变量当中
当在main()
方法调用get()
方法获取结果时,会进入一个循环判断当中,当结果还没被计算出来,会调用LockSupport.park()
使线程阻塞,直到结果被保存到outcome
当中,调用LockSupport.unpark()
解锁,此时get()
方法不在阻塞,返回出结果.