JUC锁框架源码阅读-Future和Callable
使用方法
public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newFixedThreadPool(2); /** * 异步执行耗时统计操作 */ Future<Integer> future = executorService.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { //模拟耗时统计 Thread.sleep(5000); return 5; } }); //不用串行等待统计 先执行其他数据组装 System.out.println("组装数据1"); System.out.println("组装数据2"); //如果统计操作没有执行完则等待 Integer i= (Integer) future.get(); //统一返回结果 System.out.println("返回组装数据,耗时统计:"+i); }
我们往往都是配合线程池使用。继续往下看
<1>submit
java.util.concurrent.AbstractExecutorService#submit(java.util.concurrent.Callable<T>)
public <T> Future<T> submit(Callable<T> task) { if (task == null) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; }
java.util.concurrent.AbstractExecutorService#newTaskFor
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { return new FutureTask<T>(callable); }
可以发现我们最终返的FutureTask
类图
可以看到FutureTask实现了Runnable
RunnableFuture接口定义
/** * runnable和Future都需要具体实现类实现 * @param <V> */ public interface RunnableFuture<V> extends Runnable, Future<V> { void run();
Future接口定义
public interface Future<V> { /** * 取消当前的Future。会唤醒所有等待结果值的线程,抛出CancellationException异常 * @param mayInterruptIfRunning 是否中断 计算结果值的那个线程 * @return 返回true表示取消成功 */ boolean cancel(boolean mayInterruptIfRunning); // 当前的Future是否被取消,返回true表示已取消。 boolean isCancelled(); // 当前Future是否已结束。包括运行完成、抛出异常以及取消,都表示当前Future已结束 boolean isDone(); // 获取Future的结果值。如果当前Future还没有结束,那么当前线程就等待, // 直到Future运行结束,那么会唤醒等待结果值的线程的。 V get() throws InterruptedException, ExecutionException; // 获取Future的结果值。与get()相比较多了允许设置超时时间。 V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException; }
Callable接口定义
public interface Callable<V> { /** * 与runable不同的是增加了返回值 * * @return computed result * @throws Exception if unable to compute a result */ V call() throws Exception; }
FutureTask状态定义
// 表示FutureTask当前的状态 private volatile int state; // NEW 新建状态,表示这个FutureTask还没有开始运行 private static final int NEW = 0; // COMPLETING 完成状态, 表示FutureTask任务已经计算完毕了, // 但是还有一些后续操作,例如唤醒等待线程操作,还没有完成。 private static final int COMPLETING = 1; // FutureTask任务完结,正常完成,没有发生异常 private static final int NORMAL = 2; // FutureTask任务完结,因为发生异常。 private static final int EXCEPTIONAL = 3; // FutureTask任务完结,因为取消任务 private static final int CANCELLED = 4; // FutureTask任务完结,也是取消任务,不过发起了中断运行任务线程的中断请求。 private static final int INTERRUPTING = 5; // FutureTask任务完结,也是取消任务,已经完成了中断运行任务线程的中断请求。 private static final int INTERRUPTED = 6;
FutureTask
run
public void run() { /** * 1.如果状态state不是NEW * 2.cas设置runner失败,表示已经由其他线程抢先设置了 * 保证了只有一个线程可以运行try 代码块中的代码。 */ if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread())) return; try { //获得Callable具体任务是吸纳 Callable<V> c = callable; //如果Callable任务不为空 同时任务还没有开始过执行callable任务 if (c != null && state == NEW) { V result; boolean ran; try { //执行call任务 发挥具体值 result = c.call(); //执行完毕 ran = true; } catch (Throwable ex) { //出现异常 result = null; ran = false; //<1>设置异常 设置状态state为EXCEPTIONAL 同时唤醒其他等待结果的线程 setException(ex); } //<2>执行成保存结果 设置sate为COMPLETING 同时唤醒其他等待结果的线程 if (ran) set(result); } } finally { runner = null; int s = state; // 当状态大于或等于INTERRUPTING,调用handlePossibleCancellationInterrupt方法, // 等待别的线程将状态设置成INTERRUPTED if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); } }
<1>setException
protected void setException(Throwable t) { //CAS将状态改为COMPLETING if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { outcome = t; //CAS将状态改为EXCEPTIONAL UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state finishCompletion(); } }
<2>set
protected void set(V v) { //cas修改状态为COMPLETING if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) { //保存结果 outcome = v; //CAS修改状态为NORMAL UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state //唤醒等待线程 finishCompletion(); } }
<3>finishCompletion
private void finishCompletion() { // 循环唤醒等待线程 for (FutureTask.WaitNode q; (q = waiters) != null;) { if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) { for (;;) { Thread t = q.thread; if (t != null) { q.thread = null; LockSupport.unpark(t); } FutureTask.WaitNode next = q.next; if (next == null) break; q.next = null; // unlink to help gc q = next; } break; } } //空实现 子类可以实现 done(); callable = null; // to reduce footprint }
get
public V get() throws InterruptedException, ExecutionException { int s = state; //表示未开始执行 或者 执行完成还没组装完结果 if (s <= COMPLETING) /<1>自旋根据状态获取结果,判断是否阻塞,默认没有超时时间 s = awaitDone(false, 0L); //<4>根据状态判断是否发生异常 是抛出异常还是 正常返回结果 return report(s); }
<1>awaitDone
private int awaitDone(boolean timed, long nanos) throws InterruptedException { //如果有超时时间计算截止时间 final long deadline = timed ? System.nanoTime() + nanos : 0L; FutureTask.WaitNode q = null; // 节点是否已添加 boolean queued = false; for (;;) { // 如果当前线程中断标志位是true, // <3>那么从列表中移除节点q,并抛出InterruptedException异常 if (Thread.interrupted()) { removeWaiter(q); throw new InterruptedException(); } //获得状态 int s = state; // 当状态大于COMPLETING时,表示FutureTask任务已结束。 if (s > COMPLETING) { if (q != null) // 将节点q线程设置为null,因为线程没有阻塞等待 q.thread = null; return s; } // 表示还有一些后序操作没有完成,那么当前线程让出执行权 else if (s == COMPLETING) // cannot time out yet Thread.yield(); else if (q == null) // 使用当前线程创建节点p q = new FutureTask.WaitNode(); else if (!queued) // 使用CAS函数将新节点添加到链表中,如果添加失败,那么queued为false, // 下次循环时,会继续添加,直到成功。 queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q); else if (timed) { // timed为true表示需要设置超时 nanos = deadline - System.nanoTime(); //超时时间已经过了 则从队列移除 if (nanos <= 0L) { removeWaiter(q); return state; } //现在阻塞 指定时间 等待唤醒 LockSupport.parkNanos(this, nanos); } else //线程阻塞 等待唤醒 LockSupport.park(this); } }
<3>removeWaiter
// 从链表中删除节点node private void removeWaiter(WaitNode node) { if (node != null) { // 将thread设置null node.thread = null; retry: for (;;) { // restart on removeWaiter race for (WaitNode pred = null, q = waiters, s; q != null; q = s) { // 记录当前节点q的下一个节点s s = q.next; // 如果当前节点q的thread不等于null,那么就用pred记录q if (q.thread != null) pred = q; // 如果当前节点q的thread等于null,且pred不等于null else if (pred != null) { // 删除当前节点q pred.next = s; // 如果pred.thread == null,那么继续retry的for循环 if (pred.thread == null) // check for race continue retry; } else if (!UNSAFE.compareAndSwapObject(this, waitersOffset, q, s)) continue retry; } break; } } }
<4>report
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); }
标签:
并发编程
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!