java - java Guava ThreadFactoryBuilder 为什么我们需要计数为 AtomicLong
问题描述
private static ThreadFactory doBuild(ThreadFactoryBuilder builder) {
final String nameFormat = builder.nameFormat;
final Boolean daemon = builder.daemon;
final Integer priority = builder.priority;
final UncaughtExceptionHandler uncaughtExceptionHandler = builder.uncaughtExceptionHandler;
final ThreadFactory backingThreadFactory =
(builder.backingThreadFactory != null)
? builder.backingThreadFactory
: Executors.defaultThreadFactory();
final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;
return new ThreadFactory() {
@Override
public Thread newThread(Runnable runnable) {
Thread thread = backingThreadFactory.newThread(runnable);
if (nameFormat != null) {
thread.setName(format(nameFormat, count.getAndIncrement()));
}
if (daemon != null) {
thread.setDaemon(daemon);
}
if (priority != null) {
thread.setPriority(priority);
}
if (uncaughtExceptionHandler != null) {
thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
}
return thread;
}
};
}
最近我开始研究在线程池中创建新线程ThreadFactory
使用哪个。ThreadPoolExecutor
为了方便调试和监控,我们不希望线程池创建的线程是默认的0、1、2、3,而是取一个有意义的名字。
实现这一目标的一种方法是实现一个自定义ThreadLoad
的,可以在创建线程时设置线程的名称。Guava有一个方便的自定义构建器类ThreadFactory
,我希望从中学习。
理解这个类的大部分内容并不难,但我对方法count
中的变量感到很困惑。doBuild
我还去了实际调用的ThreadPoolExecutor#Worker
源代码newThread()
。ThreadFactory
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
但我仍然不清楚为什么我们需要一个原子变量。
当然,我可以猜测线程池中的线程可能是以多线程方式创建的,因此为了确保线程的 id 不会重复,我们需要 id-generator 是一个原子变量,但我没有直接证据这个假设呢。
任何人都可以对此有所了解吗?
解决方案
我怀疑你会找到任何
直接证据
在代码中。只有3种可能:
- 作者在代码中的注释解释了
AtomicLong
用于线程安全的原因。但这仍然是间接证据,因为作者的假设可能是错误的(他不是)。 - 检查
count
在某些多线程场景中是否正确更新的测试。但这又是间接证据,因为它表明count
正确更新了,而不是在其他情况下会错误地更新。 - 而唯一的直接证据将是有错误的测试。为此,您需要在没有
AtomicLong
...的情况下测试一个代码版本。好吧,您可以这样做。
但如果你明白这一点
线程池中的线程可以以多线程方式创建,因此为了确保线程的 id 不会重复,我们需要 id-generator 是一个原子变量
你还需要什么?心理实验(与第三个项目中的测试不同)非常简单:
newThread
被称为Thread1
- 它到达了需要更新的地步
count
- 读取的值,
count
并将其放入寄存器中。 - 的值在寄存器
count
中递增,但尚未写入存储的内存。count
- 此时上下文被切换。
newThread
fromThread1
暂停。newThread
再次调用但从Thread2
- 当我们需要更新
count
- 哎呀!
Thread2
无法count
从寄存器中读取更新后的值。它可以从内存中读取它,但仍然有一个旧值。
推荐阅读
- jsf - 如何在 JSF 中添加标题
- c# - 基础提供程序在打开时失败。连接没有关闭。连接的当前状态是正在连接。问题
- python-3.x - 如何在字符串之后获取几个字符以便能够识别字符串是在头标签或列表项中?
- ansible - Ansible vars_prompt & with_items 和拆分
- go - 通过 API Gateway 使用表单数据将图像发布到 Lambda 函数会导致文件无效
- google-bigquery - Google BigQuery:合并语句
- javascript - react-native FlatList 显示 - 顶部的空白
- wso2 - WSO2 ESB 还存在吗?
- html - 网格 - HTML | CSS
- sharepoint-2016 - 在 Sharepoint 2016 多服务器场中安装 Visual Studio