一、What
1. java创建多线程的方式
a. Thread, 没有执行结果,既没有数据也没有异常
b. ThreadPool,减少线程创建和销毁的开销
c. Runnable,只有一个run()方法,没有执行结果,被Thread执行;如果要获得返回结果,可以使用共享变量或者线程通信的方法
d. Callable,只有一个call()方法,是Runnable的补充,有返回值也有异常,返回的是泛型结果
e. Future,先生成一个凭据而不是结果,不阻塞接下来的操作,然后通过凭据获取结果,用于异步计算
2. FutureTask类实现了Future接口,是Future的一个基本实现
3. 可以把Callable的实例作为FutureTask的参数,生成一个FutureTask的实例,把这个实例作为Runnable,作为参数启动一个线程
二、How
1. Callable接口, 配合ExecutorService里的submit()方法使用,是为了获取返回值
2. Future接口,isDone()方法查看异步操作是否完成,get()方法返回结果,是为了异步
3. FutureTask类
a. 实现了Runnable接口和Future接口,综合了异步和返回结果的功能
b. FutureTask的对象没有返回值,是一个Runnable;但是内部会把Runnable转换为Callable,有返回值;最终的返回值用get()方法获取,而不是直接返回
c. 有一个回调函数done(),任务结束时会被触发;而Future没有此功能,只能判断任务是否结束,然后手动操作
三、使用场景(When)
1. 耗时计算,主线程完成自己的任务后,再获取子线程的计算结果
2. 高并发环境下只执行一次,例如数据库链接的建立
四、Why(原理)
1. FutureTask的状态字段,表示当前线程的状态的转换
* Possible state transitions: * 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;
2. FutureTask的run()方法源码,主要逻辑就是执行Callable的call()方法,把结果保存在全局变量里,相当于对Runnable的一次封装
public void run() { if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { Callable<V> c = callable; // 这里的callable是从构造方法里面传人的,虽然FutureTask的实例是Runnable,但最终使用的是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); // 保存call方法抛出的异常,而不是直接抛出 } if (ran) set(result); // 保存call方法的执行结果 } } 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); } }
3. get()方法源码,使用死循环阻塞,直到从全局变量里拿到结果
public V get() throws InterruptedException, ExecutionException { int s = state; if (s <= COMPLETING) s = awaitDone(false, 0L); return report(s); } private int awaitDone(boolean timed, long nanos) throws InterruptedException { final long deadline = timed ? System.nanoTime() + nanos : 0L; WaitNode q = null; boolean queued = false; for (;;) { if (Thread.interrupted()) { removeWaiter(q); throw new InterruptedException(); } int s = state; if (s > COMPLETING) { if (q != null) q.thread = null; return s; } else if (s == COMPLETING) // cannot time out yet Thread.yield(); else if (q == null) q = new WaitNode(); else if (!queued) queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q); else if (timed) { nanos = deadline - System.nanoTime(); if (nanos <= 0L) { removeWaiter(q); return state; } LockSupport.parkNanos(this, nanos); } else LockSupport.park(this); } }
参考: