为什么jvm在fixedThreadPool的情况下重新创建线程池而在cachedThreadPool的情况下不这样做?

时间:2017-02-17 10:10:55

标签: java multithreading threadpool threadpoolexecutor jvisualvm

我有代码示例:

public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 100; i++) {
            if (test() != 5 * 100) {
                throw new RuntimeException("main");
            }
        }
        test();

    }

    private static long test() throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(100);
        CountDownLatch countDownLatch = new CountDownLatch(100 * 5);
        Set<Thread> threads = Collections.synchronizedSet(new HashSet<>());
        AtomicLong atomicLong = new AtomicLong();
        for (int i = 0; i < 5 * 100; i++) {
            Thread.sleep(100);
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        threads.add(Thread.currentThread());
                        atomicLong.incrementAndGet();
                        countDownLatch.countDown();
                        Thread.sleep(1000);
                    } catch (Exception e) {
                        System.out.println(e);
                    }


                }
            });
        }
        executorService.shutdown();
        countDownLatch.await();
        if (threads.size() != 100) {
            throw new RuntimeException("test");
        }
        return atomicLong.get();
    }
}

我特别申请工作很久。

我看到了jvisualVM 每次重新创建间隙线程池。

几分钟后,我看到了:

enter image description here

但如果我使用newCachedThreadPool代替newFixedThreadPool,我会看到不变的情况:

enter image description here

你能解释一下这种行为吗?

P.S。

问题是代码中发生异常而第二次迭代未启动

3 个答案:

答案 0 :(得分:2)

回答你的问题;看看这里:

private static long test() throws InterruptedException {
  ExecutorService executorService = Executors.newFixedThreadPool(100);

JVM在test()的每次运行期间创建一个新的ThreadPool,因为你告诉它这样做。

换句话说:如果您打算重新使用 相同的线程池,请避免始终创建/关闭您的实例。

从这个意义上说,简单的解决方法是:将ExecutorService的创建移动到main()方法中;并将服务作为参数传递给您的test()方法。

编辑:关于你对缓存与固定线程池的最后评论;你可能想看看这个question

答案 1 :(得分:0)

因为您在代码中询问过它? :)

尝试在测试之外移动池创建代码。

答案 2 :(得分:0)

来自docs:

的newFixedThreadPool

  

创建一个线程池,该线程池重用在共享无界队列中运行的固定数量的线程。在任何时候,最多nThreads线程将是活动的处理任务。如果在所有线程都处于活动状态时提交了其他任务,则它们将在队列中等待,直到线程可用。如果任何线程由于在关闭之前执行期间的故障而终止,则在需要执行后续任务时将使用新的线程。池中的线程将一直存在,直到明确关闭为止。

newCachedThreadPool

  

创建一个根据需要创建新线程的线程池,但在它们可用时将重用以前构造的线程。这些池通常会提高执行许多短期异步任务的程序的性能。如果可用,执行调用将重用先前构造的线程。如果没有可用的现有线程,则将创建一个新线程并将其添加到池中。未使用60秒的线程将终止并从缓存中删除。因此,长时间闲置的池不会消耗任何资源。请注意,可以使用ThreadPoolExecutor构造函数创建具有相似属性但不同详细信息的池(例如,超时参数)。