有 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提供了一个方便的生成器类,我希望从中学习

理解这个类的大部分内容并不难,但我对doBuild方法中的count变量感到非常困惑

我还访问了ThreadPoolExecutor#Worker的源代码,其中ThreadFactorynewThread()实际上被调用

        Worker(Runnable firstTask) {
            setState(-1); // inhibit interrupts until runWorker
            this.firstTask = firstTask;
            this.thread = getThreadFactory().newThread(this);
        }

但我仍然不清楚为什么我们需要一个原子变量

当然,我可以猜测线程池中的线程可能是以多线程方式创建的,因此为了确保线程的id不会被复制,我们需要id生成器作为一个原子变量,但我还没有直接的证据支持这个假设

有人能解释一下吗


共 (1) 个答案

  1. # 1 楼答案

    我怀疑你找不到

    direct evidence

    在代码中。只有三种可能性:

    1. 作者在代码中解释AtomicLong用于线程安全的注释。但这仍然是间接证据,因为作者的假设可能是错误的(事实并非如此)
    2. 检查count在某些多线程场景中是否正确更新的测试。但这又是间接证据,因为它表明count正确更新了,而不是在其他情况下,错误更新了
    3. 唯一直接的证据将是带有错误的测试。为此,您需要测试一个不带AtomicLong的代码版本。。。好吧,你可以做到

    但如果你明白的话

    the threads in the thread pool may be created in a multi-threading way thus to ensure the id of the threads not get duplicated we need the id-generator to be a atomic variable

    你还需要什么? 心理实验(与第三颗子弹的测试不同)非常简单:

    1. newThreadThread1调用
    2. 它需要更新count
    3. 读取count,并将其放入寄存器中
    4. 在寄存器中count递增,但尚未写入存储count内存
    5. 此时,背景发生了变化^来自Thread1的{}暂停newThread再次被调用,但来自Thread2
    6. 我们需要更新count
    7. 哎呀!Thread2无法从寄存器读取count的更新值。它可以从内存中读取,但仍然有一个旧值