**FutureTask应用源码分析**(二)

2024-01-17 09:28

本文主要是介绍**FutureTask应用源码分析**(二),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.3.3 FutureTask的set&setException方法

任务执行完毕后,修改任务的状态以及封装任务的结果

// 没有异常的时候,正常返回结果
protected void set(V v) {
// 因为任务执行完毕,需要将任务的状态从NEW,修改为COMPLETING
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
// 将返回结果赋值给 outcome 属性
outcome = v;
// 将任务状态变为NORMAL,正常结束
UNSAFE.putOrderedInt(this, stateOffset, NORMAL);
// 一会再说……
finishCompletion();
}
}
// 任务执行期间出现了异常,这边要封装结果
protected void setException(Throwable t) {
// 因为任务执行完毕,需要将任务的状态从NEW,修改为COMPLETING
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
// 将异常信息封装到 outcome 属性
outcome = t;
// 将任务状态变为EXCEPTIONAL,异常结束
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL);
// 一会再说……
finishCompletion();
}
}

1.3.4 FutureTask的cancel方法

任务取消的一个方式
● 任务直接从NEW状态转换为CANCEL
● 任务从NEW状态变成INTERRUPTING,然后再转换为INTERRUPTED

// 取消任务操作
public boolean cancel(boolean mayInterruptIfRunning) {
// 查看任务的状态是否是NEW,如果NEW状态,就基于传入的参数mayInterruptIfRunning
// 决定任务是直接从NEW转换为CANCEL,还是从NEW转换为INTERRUPTING
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
try {
// 如果mayInterruptIfRunning为true
// 就需要中断线程
if (mayInterruptIfRunning) {
try {
// 拿到任务线程
Thread t = runner;
if (t != null)
// 如果线程不为null,直接interrupt
t.interrupt();
} finally {
// 将任务状态设置为INTERRUPTED
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);}
}
} finally {
// 任务结束后的一些处理~~ 一会看~~
finishCompletion();
}
return true;
}

1.3.5 FutureTask的get方法

这个是线程获取FutureTask任务执行结果的方法

// 拿任务结果
public V get() throws InterruptedException, ExecutionException {
// 获取任务的状态
int s = state;
// 要么是NEW,任务还没执行完
// 要么COMPLETING,任务执行完了,结果还没封装好。
if (s <= COMPLETING)
// 让当前线程阻塞,等待结果
s = awaitDone(false, 0L);
// 最终想要获取结果,需要执行report方法
return report(s);
}
// 线程等待FutureTask结果的过程
private int awaitDone(boolean timed, long nanos) throws InterruptedException {
// 针对get方法传入了等待时长时,需要计算等到什么时间点
final long deadline = timed ? System.nanoTime() + nanos : 0L;
// 声明好需要的Node,queued:放到链表中了么?
WaitNode q = null;
boolean queued = false;
for (;;) {
// 查看线程是否中断,如果中断,从等待链表中移除,甩个异常
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
// 拿到状态
int s = state;
// 到这,说明任务结束了。
if (s > COMPLETING) {
if (q != null)
// 如果之前封装了WaitNode,现在要清空
q.thread = null;
return s;
}
// 如果任务状态是COMPLETING,这就不需要去阻塞线程,让步一下,等待一小会,结果就有了
else if (s == COMPLETING)
Thread.yield();
// 如果还没初始化WaitNode,初始化
else if (q == null)q = new WaitNode();
// 没放队列的话,直接放到waiters的前面
else if (!queued)
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
// 准备挂起线程,如果timed为true,挂起一段时间
else if (timed) {
// 计算出最多可以等待多久
nanos = deadline - System.nanoTime();
// 如果等待的时间没了
if (nanos <= 0L) {
// 移除当前的Node,返回任务状态
removeWaiter(q);
return state;
}
// 等一会
LockSupport.parkNanos(this, nanos);
}
else
// 死等
LockSupport.park(this);
}
}
// get的线程已经可以阻塞结束了,基于状态查看能否拿到返回结果
private V report(int s) throws ExecutionException {
// 拿到outcome 返回结果Object x = outcome;
// 如果任务状态是NORMAL,任务正常结束,返回结果
if (s == NORMAL)
return (V)x;
// 如果任务状态大于等于取消
if (s >= CANCELLED)
// 直接抛出异常
throw new CancellationException();
// 到这就是异常结束
throw new ExecutionException((Throwable)x);
}

1.3.6 FutureTask的finishCompletion方法

只要任务结束了,无论是正常返回,异常返回,还是任务被取消都会执行这个方法
而这个方法其实就是唤醒那些执行get方法等待任务结果的线程

// 任务结束后触发
private void finishCompletion() {
// 在任务结束后,需要唤醒
for (WaitNode q; (q = waiters) != null;) {
// 第一步直接以CAS的方式将WaitNode置为null
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (;;) {
// 拿到了Node中的线程
Thread t = q.thread;// 如果线程不为null
if (t != null) {
// 第一步先置位null
q.thread = null;
// 直接唤醒这个线程
LockSupport.unpark(t);
}
// 拿到当前Node的next
WaitNode next = q.next;
// next为null,代表已经将全部节点唤醒了吗,跳出循环
if (next == null)
break;
// 将next置位null
q.next = null;
// q的引用指向next
q = next;
}
break;
}
}
// 任务结束后,可以基于这个扩展方法,记录一些信息
done();
// 任务执行完,把callable具体任务置位null
callable = null;
}

这篇关于**FutureTask应用源码分析**(二)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/615566

相关文章

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

最长公共子序列问题的深度分析与Java实现方式

《最长公共子序列问题的深度分析与Java实现方式》本文详细介绍了最长公共子序列(LCS)问题,包括其概念、暴力解法、动态规划解法,并提供了Java代码实现,暴力解法虽然简单,但在大数据处理中效率较低,... 目录最长公共子序列问题概述问题理解与示例分析暴力解法思路与示例代码动态规划解法DP 表的构建与意义动

C#使用DeepSeek API实现自然语言处理,文本分类和情感分析

《C#使用DeepSeekAPI实现自然语言处理,文本分类和情感分析》在C#中使用DeepSeekAPI可以实现多种功能,例如自然语言处理、文本分类、情感分析等,本文主要为大家介绍了具体实现步骤,... 目录准备工作文本生成文本分类问答系统代码生成翻译功能文本摘要文本校对图像描述生成总结在C#中使用Deep

5分钟获取deepseek api并搭建简易问答应用

《5分钟获取deepseekapi并搭建简易问答应用》本文主要介绍了5分钟获取deepseekapi并搭建简易问答应用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需... 目录1、获取api2、获取base_url和chat_model3、配置模型参数方法一:终端中临时将加

JavaScript中的isTrusted属性及其应用场景详解

《JavaScript中的isTrusted属性及其应用场景详解》在现代Web开发中,JavaScript是构建交互式应用的核心语言,随着前端技术的不断发展,开发者需要处理越来越多的复杂场景,例如事件... 目录引言一、问题背景二、isTrusted 属性的来源与作用1. isTrusted 的定义2. 为

Go中sync.Once源码的深度讲解

《Go中sync.Once源码的深度讲解》sync.Once是Go语言标准库中的一个同步原语,用于确保某个操作只执行一次,本文将从源码出发为大家详细介绍一下sync.Once的具体使用,x希望对大家有... 目录概念简单示例源码解读总结概念sync.Once是Go语言标准库中的一个同步原语,用于确保某个操

Python调用另一个py文件并传递参数常见的方法及其应用场景

《Python调用另一个py文件并传递参数常见的方法及其应用场景》:本文主要介绍在Python中调用另一个py文件并传递参数的几种常见方法,包括使用import语句、exec函数、subproce... 目录前言1. 使用import语句1.1 基本用法1.2 导入特定函数1.3 处理文件路径2. 使用ex

Redis主从/哨兵机制原理分析

《Redis主从/哨兵机制原理分析》本文介绍了Redis的主从复制和哨兵机制,主从复制实现了数据的热备份和负载均衡,而哨兵机制可以监控Redis集群,实现自动故障转移,哨兵机制通过监控、下线、选举和故... 目录一、主从复制1.1 什么是主从复制1.2 主从复制的作用1.3 主从复制原理1.3.1 全量复制

将Python应用部署到生产环境的小技巧分享

《将Python应用部署到生产环境的小技巧分享》文章主要讲述了在将Python应用程序部署到生产环境之前,需要进行的准备工作和最佳实践,包括心态调整、代码审查、测试覆盖率提升、配置文件优化、日志记录完... 目录部署前夜:从开发到生产的心理准备与检查清单环境搭建:打造稳固的应用运行平台自动化流水线:让部署像

Redis主从复制的原理分析

《Redis主从复制的原理分析》Redis主从复制通过将数据镜像到多个从节点,实现高可用性和扩展性,主从复制包括初次全量同步和增量同步两个阶段,为优化复制性能,可以采用AOF持久化、调整复制超时时间、... 目录Redis主从复制的原理主从复制概述配置主从复制数据同步过程复制一致性与延迟故障转移机制监控与维