多线程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
提供了一个方便的生成器类,我希望从中学习
理解这个类的大部分内容并不难,但我对doBuild
方法中的count
变量感到非常困惑
我还访问了ThreadPoolExecutor#Worker
的源代码,其中ThreadFactory
的newThread()
实际上被调用
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
但我仍然不清楚为什么我们需要一个原子变量
当然,我可以猜测线程池中的线程可能是以多线程方式创建的,因此为了确保线程的id不会被复制,我们需要id生成器作为一个原子变量,但我还没有直接的证据支持这个假设
有人能解释一下吗
# 1 楼答案
我怀疑你找不到
在代码中。只有三种可能性:
AtomicLong
用于线程安全的注释。但这仍然是间接证据,因为作者的假设可能是错误的(事实并非如此)李>count
在某些多线程场景中是否正确更新的测试。但这又是间接证据,因为它表明count
正确更新了,而不是在其他情况下,错误更新了李>AtomicLong
的代码版本。。。好吧,你可以做到李>但如果你明白的话
你还需要什么? 心理实验(与第三颗子弹的测试不同)非常简单:
newThread
从Thread1
调用count
count
的值,并将其放入寄存器中李>count
的值递增,但尚未写入存储count
的内存李>Thread1
的{newThread
再次被调用,但来自Thread2
count
Thread2
无法从寄存器读取count
的更新值。它可以从内存中读取,但仍然有一个旧值李>