FutureTask的使用方法及实现原理,Java后端路线图

本文详细介绍了FutureTask的工作原理,包括构造函数中对volatile变量的处理、使用Treiber栈保存等待线程、取消操作的实现、等待线程的get()方法以及计算线程的run()方法。同时,提到了FutureTask在并发控制和无锁数据结构中的应用,并提供了相关面试题解析和学习资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

this.state = NEW; // ensure visibility of callable

}

在FutureTask的构造函数中,对声明为volatile的state变量进行赋值操作后,callable变量也会变得对于其他线程可见

2. 用一个Treiber栈保存等待线程

Treiber栈是一个无锁数据结构,FutureTask中的waiters变量指向这个栈的栈顶。名字有点吓人,其实很简单,就是一个无锁的线程安全的栈。入栈操作只通过一步CAS操作实现,即修改栈顶指针waiters;出栈和在栈的中间执行删除操作通过特定的循环操作实现。

3. 取消操作cancel()的实现

cancel操作首先判断state是否等于NEW,即判断计算线程(runner)是否已经开始。如果没有开始执行,则立即用CAS操作将状态改为CANCELED或INTERRUPTING,防止runner开始执行计算工作。判断了state之后,紧接着用compareAndSwap对state进行修改而不是覆盖式的赋值,这是考虑到在判断state和修改state之间,state可能被其他线程修改。顺便讲一下,state的判断后面紧跟CAS操作,可以让两个原子操作合并成一个原子操作,

state == NEW && UNSAFE.compareAndSwapInt(this, stateOffset, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED) Java开源项目【ali1024.coding.net/public/P7/Java/git】

如果状态已经不是NEW,说明runner已经开始,此时根据入参mayInterruptIfRunning来决定是否给runner发中断。接下来,把Treiber栈中的等待线程全部唤醒并且移出。这里的唤醒动作考虑到可能有多个线程并发调用cancel(),所以设计了一个循环CAS操作,对Treiber栈操作竞争,保证只有一个线程能够进入内层循环,代码如下:

private void finishCompletion() {

for (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);

}

WaitNode next = q.next;

if (next == null)

break;

q.next = null; // unlink to help gc

q = next;

}

break;

}

}

done();

callable = null;

}

基于循环CAS操作对一个数据结构进行修改,是实现无锁数据结构的常用套路。

4. 等待线程中的等待操作get()的实现

等待线程在启动FutureTask执行,在必须访问其计算结果的时候调用get()。如果此时计算结果已经出来,则get()不会阻塞,直接把outcome变量中保存的记过返回;如果还未计算完成,则会执行一个等待循环。这个等待循环与AQS加锁操作中的循环类似,但有些不同,比如它管理一个等待线程。这个循环不断的检查中断状态和state:如果遇到中断则退出;如果state表示计算结束则退出;如果state=COMPLETING,则自旋;如果已经超时,则退出;其他情况阻塞。FutureTask.get()的阻塞操作就是由这个循环实现的,具体见get()和awaitDone()方法的代码。

5. 计算线程所调用的run()方法的实现

计算线程,例如线程池中的worker,通过调用FutureTask.run()开始执行计算工作。请参照FutureTask.run的代码,如下(建议对照代码阅读)。

public void run() {

if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset,

null, Thread.currentThread()))

return;

try {

Callable c = callable 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》开源 ;

if (c != null && state == NEW) {

V result;

boolean ran;

最后

看完上述知识点如果你深感Java基础不够扎实,或者刷题刷的不够、知识不全面

小编专门为你量身定制了一套<Java一线大厂高岗面试题解析合集:JAVA基础-中级-高级面试+SSM框架+分布式+性能调优+微服务+并发编程+网络+设计模式+数据结构与算法>

image

针对知识面不够,也莫慌!还有一整套的<Java核心进阶手册>,可以瞬间查漏补缺

image

全都是一丢一丢的收集整理纯手打出来的

更有纯手绘的各大知识体系大纲,可供梳理:Java筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~

image

image
a筑基、MySQL、Redis、并发编程、Spring、分布式高性能架构知识、微服务架构知识、开源框架知识点等等的xmind手绘图~

[外链图片转存中…(img-F57pabgI-1650617229163)]

[外链图片转存中…(img-yhcVYMOe-1650617229164)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值