Java 线程正在ThreadPoolExecutor中等待

Java 线程正在ThreadPoolExecutor中等待,java,threadpool,Java,Threadpool,这段代码运行非常慢。我转储了线程,几乎有一个线程同时运行,但是当我将ExecutorService更改为ForkJoinPool时,代码运行得非常快。我不知道为什么线程在等待,我的计算机有8个内核 公共类测试{ 公共静态void main(字符串[]args)引发InterruptedException{ int NUM_OF_线程=8; int NUM_OF_增量=100_000_000; //ExecutorService=Executors.newWorkStealingPool();

这段代码运行非常慢。我转储了线程,几乎有一个线程同时运行,但是当我将
ExecutorService
更改为
ForkJoinPool
时,代码运行得非常快。我不知道为什么线程在等待,我的计算机有8个内核

公共类测试{
公共静态void main(字符串[]args)引发InterruptedException{
int NUM_OF_线程=8;
int NUM_OF_增量=100_000_000;
//ExecutorService=Executors.newWorkStealingPool();
ExecutorService=Executors.newFixedThreadPool(线程数);
最终计数器=新的StupidCounter();
很久以前=System.currentTimeMillis();
对于(int i=0;i

“pool-1-thread-7”#17 prio=5 os_prio=31 tid=0x00007faaa481c000 nid=0x6503等待条件[0x0000700001d6d000]
java.lang.Thread.State:等待(停车)
在sun.misc.Unsafe.park(本机方法)
-停车等待(java.util.concurrent.locks.ReentrantLock$NonfairSync)
位于java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
位于java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
在java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly处(AbstractQueuedSynchronizer.java:897)
位于java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
在java.util.concurrent.locks.ReentrantLock.lockInterruptablely(ReentrantLock.java:335)处
位于java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:439)
位于java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
位于java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
位于java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
运行(617Thread.java:745)

很难从这段代码中得出任何真正的结论,因为它实际上什么都没有做。执行器的内部队列是瓶颈,这就是为什么一次只能看到一个线程“工作”。它实际上不工作,它从队列中获取下一个任务,使所有其他线程(也获取下一个任务)等待。除了
LinkedBlockingQueue.take()
的功能外,您并没有在这里真正测试任何东西


increment()
方法不是线程安全的,因此基本上您测试的是错误的代码,结果几乎不相关。如果让
反请求
任务执行实际的工作,这需要几毫秒,那么与使用FixedThreadPool时的
ForkJoinPool
相比,您会发现性能上的差异要小得多(如果有的话),因为程序消耗了大量的时间,所以大部分时间都用于垃圾收集。我尝试使用VM参数-Xmx3g执行,但当VM试图避免内存耗尽时,仍然陷入垃圾收集

您可能希望使用内存转储来深入了解消耗的根本原因,但我猜这是计数器中的实例

无论如何,根本原因似乎是使用LinkedBlockingQueue作为工作队列的FixedThreadPool。由于for循环向工作队列中添加了100_000_000个元素,因此很少有其他线程从中获取元素。因此,他们大部分时间都在等待所有的反诉提交

ForkJoinPool使用了一种更无阻塞的方式,据我所知,提交的操作有多个工作队列

public class Tests {

    public static void main(String[] args) throws InterruptedException {

        int NUM_OF_THREADS = 8;
        int NUM_OF_INCREMENTS = 100_000_000;
        //ExecutorService service = Executors.newWorkStealingPool();
        ExecutorService service = Executors.newFixedThreadPool(NUM_OF_THREADS);
        final Counter counter = new StupidCounter();

        long before = System.currentTimeMillis();
        for (int i = 0; i < NUM_OF_INCREMENTS; i++) {
            service.submit(newCounterClient(counter, i));
        }
        service.shutdown();
        service.awaitTermination(1, TimeUnit.MINUTES);
        long end = System.currentTimeMillis();
        System.out.println(end - before);
        System.out.println(counter.getCounter());
    }


    static class CounterClient implements Runnable {
        private Counter counter;
        private int num;

        public CounterClient(Counter counter, int num) {
            this.counter = counter;
            this.num = num;
        }

        @Override
        public void run() {
            counter.increment();
        }
    }

    static interface Counter {
        void increment();

        long getCounter();
    }

    static class StupidCounter implements Counter {
        long i = 0;

        @Override
        public void increment() {
            i++;
        }

        @Override
        public long getCounter() {
            return i;
        }
    }

}
"pool-1-thread-7" #17 prio=5 os_prio=31 tid=0x00007faaa481c000 nid=0x6503 waiting on condition [0x0000700001d6d000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000006c006b3d8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:897)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
    at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:439)
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(617Thread.java:745)