猿问

是否有必要在 ThreadFactory 中使用 AtomicInteger?

我认为有必要AtomicInteger在 ThreadFactory 中使用,但是当我试图向自己证明它时,我失败了。


    new ThreadFactory() {


        private int threadId = 0;   <---- AtomicInteger preferred


        @Override

        public Thread newThread(Runnable r) {

            Thread t = new Thread(r);

            t.setDaemon(true);

            t.setName("my-thread-" + (threadId++));   <--- dangerous code

            return t;

        }

    }

如果出现多个请求,线程工厂将生成线程来处理它们,并且在生成过程中,可能会出现竞争条件潜入的间隙。


我尝试使用以下代码来证明我的理论,但2_000 个核心线程根本不会发生这种情况。


@Slf4j

public class ThreadFactoryTest {


    private ConcurrentHashMap<String, Thread> threadIdThreadMap = new ConcurrentHashMap<>();

    private ThreadPoolExecutor myExecutor = new ThreadPoolExecutor(2000, 2000, 30, TimeUnit.SECONDS,

            new ArrayBlockingQueue<>(100000), new ThreadFactory() {


        private int threadId = 0;


        @Override

        public Thread newThread(Runnable r) {

            Thread t = new Thread(r);

            t.setDaemon(true);

            t.setName("my-thread-" + (threadId++));

            if (threadIdThreadMap.contains(t.getName())) {

                log.error("already existed");

                System.err.println(myExecutor);

                myExecutor.shutdownNow();

            } else threadIdThreadMap.put(t.getName(), t);

            return t;

        }

    }, new ThreadPoolExecutor.AbortPolicy());


    @Test

    public void testThreadFactory() throws Exception {

        for (int i = 0; i < 100; ++i) {

            new Thread(() -> runOneHundredJobs()).start();

        }

        Thread.sleep(1000000);

        myExecutor.shutdown();

        myExecutor.awaitTermination(100, TimeUnit.MINUTES);

    }



看起来像一个愚蠢的问题,因为我一直都知道“很难为多线程竞争条件创造差距”。


潇潇雨雨
浏览 106回答 2
2回答

慕仙森

是否有必要在 ThreadFactory 中使用 AtomicInteger?这将取决于工厂对象的使用方式。如果您为每个实例提供不同的工厂对象,ThreadPoolExecutor那么工厂的(实际)并发要求将取决于执行程序如何使用它。如果 javadoc 中没有语句,您将需要检查源代码。我没有检查过,但我怀疑线程池的扩展(包括对 的调用newThread)发生在互斥量内。如果我的怀疑是正确的,那么这个用例不需要工厂对象是线程安全的。更新- 我现在已经检查过了,我的怀疑是不正确的(对于 Java 8 和 12)。该newThread调用是在创建新Worker对象时进行的,而在持有互斥锁时不会进行。因此,您的newThread方法在此上下文中也需要是线程安全的。如果工厂对象与其他事物(例如另一个执行程序)共享,那么您是正确的:您的newThread方法需要是线程安全的。我没有查看您的代码来尝试显示竞争条件,但在我看来,这不是解决此问题的最佳方法。代码检查和推理是更好的方法。未能证明竞争条件并不意味着它不存在。

翻翻过去那场雪

我正在使测试更简单,以使预期的结果从水下浮出水面。通过下面的测试,预期的线程大小很1000明显,而使用通常int会给出一个less大小(在我的 macOS 中为 994、996、999),但并非总是如此。public class ThreadFactoryTest {&nbsp; &nbsp; private ConcurrentHashMap<String, Thread> threadIdThreadMap = new ConcurrentHashMap<>();&nbsp; &nbsp; private ThreadPoolExecutor myExecutor = new ThreadPoolExecutor(2000, 2000, 30, TimeUnit.SECONDS,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new ArrayBlockingQueue<>(100000), new ThreadFactory() {&nbsp; &nbsp; &nbsp; &nbsp; private int threadId = 0;&nbsp; &nbsp; &nbsp; &nbsp; private AtomicInteger atomicThreadId = new AtomicInteger(0);&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public Thread newThread(Runnable r) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread t = new Thread(r);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.setDaemon(true);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.setName("my-thread-" + (threadId++));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // uncomment this line, the thread size will be less than 1000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; t.setName("my-thread-" + (atomicThreadId.getAndIncrement()));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; threadIdThreadMap.put(t.getName(), t);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return t;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }, new ThreadPoolExecutor.AbortPolicy());&nbsp; &nbsp; @Test&nbsp; &nbsp; public void testThreadFactory() throws Exception {&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i < 50; ++i) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new Thread(() -> runOneHundredJobs()).start();&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(1000000);&nbsp; &nbsp; &nbsp; &nbsp; myExecutor.shutdown();&nbsp; &nbsp; &nbsp; &nbsp; myExecutor.awaitTermination(100, TimeUnit.MINUTES);&nbsp; &nbsp; }&nbsp; &nbsp; private void runOneHundredJobs() {&nbsp; &nbsp; &nbsp; &nbsp; for (int i = 0; i < 20; ++i) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; myExecutor.execute(() -> {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while (100 < System.currentTimeMillis()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; try {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Thread.sleep(1000);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; log.warn("count: {}", threadIdThreadMap.size());&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; } catch (Exception e) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; });&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}
随时随地看视频慕课网APP

相关分类

Java
我要回答