目录
4.1 Callbale接口---FutureTask构造方法的接口
4.3 RunnableFuture接口 ---继承了Runnable,Future接口
5. 为了能站在全局的角度来看,所以画了一张流程图,感觉好丑。。。
1. 背景
我们知道线程的实现方式有4种
1.继承Thread类
2.实现Runnable接口
3.实现Callable接口:与其他明显区别是有返回值。
4.线程池
本文讲述第三种的执行流程。
刚开始感觉实现Callable接口的方法有点复杂,好奇内部到底是怎么实现的,就看了以下源码,发现代码不难,但是思路很巧妙。
2. 案例:
MyThread类实现Callable接口,泛型是返回对象的类型,这里是Integer
2.1 使用Callable线程步骤:
1.定义一个MyThread,实现Callable接口
2.重写call()方法:类似run()方法
3.创建FutureTask对象,构造方法参数是MyThread对象。
4.创建Thread对象,构造方法参数是MyThread对象。
5.开启线程
6.获取返回值,返回值保存在了FutureTask对象种,通过get()方法返回。
代码如下:
public class MyThread implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("*************************");
return 1024;
}
public static void main(String[] args)throws Exception{
FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread());
Thread thread = new Thread(futureTask);
thread.start(); //开启线程
Integer result = futureTask.get(); //获取返回值
System.out.println("result is ****"+result); //打印
}
}
测试结果:
3. 代码设计分析
我们知道Thread的构造方法参数是Runnable接口,也就是new Thread(new Runnable())这种形式,但是我们的MyThread类没有实现Runnable接口,但是RunnableFuture继承了Runnable接口,而FutureTask又实现了Runnable,所以FutureTask可以向上转型为Runnable,并作为Thread构造方法参数传入。而Callable接口的call()方法又是如何与Runnable方法联系起来的的呢?答案是:Callable的实现类MyThread作为FutureTask(相当于Runnable)的构造方法的传入参数,而Runnable的run()方法内会调用call()方法,所以就联系起来了。
总结一下执行大体流程:
thread:start()====>thread:run()====>MyThread():call()====>FutureTask:set(result)====>FutureTask:report()====>FutureTask:get()方法返回result
4. 深入Callable相关具体源码,只贴重要的部分
代码是按顺序贴的,为了思路更加清楚,贴一下自己画的流程图(和后面的一张是一样的,这里放到前面了),有点丑,不想看的忽略。。。
4.1 Callbale接口---FutureTask构造方法的接口
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
4.2 FutureTask类和内部重要方法
该类实现了RunnableFuture接口(而该接口又实现了Runnable接口,所以FutureTask可以作为Thread构造函数的参数向上转型为Runnable,这里面包含一种重要思想--运行时多态或者说时动态绑定,好处是对外提供统一接口,但是具体实现类却千变万化,妙呀!)
public class FutureTask<V> implements RunnableFuture<V> {
//构造函数
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}
//run方法
//关键代码:
//1.result = c.call(),可以看到run方法调用了call()方法
//2.set(result),可以看到运行结果通过set方法保存
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> 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);
}
if (ran)
set(result);
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
//get方法
//调用report方法返回结果,具体看report方法
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
//set方法
//关键代码:
//outcome = v;可以看到,结果包存到了outcome中
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
//report方法
//关键代码:
//Object x = outcome,return (V)x;可以看到,结果outcome赋给x然后返回了
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V)x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable)x);
}
}
4.3 RunnableFuture接口 ---继承了Runnable,Future接口
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
4.4 Runnable接口
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
4.5 Future接口
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;
}
5. 为了能站在全局的角度来看,画了一张流程图。
感觉好丑。。。可能只有我自己能看懂。。。