2016-12-16 100 views
2

此代碼運行速度非常慢。我傾銷了這些線程,並且幾乎有一個線程正在同時運行,但是當我將ExecutorService更改爲ForkJoinPool時,代碼運行速度非常快。我不知道爲什麼線程都在等待,我的電腦有8個內核...線程正在等待ThreadPoolExecutor

enter image description here

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) 

回答

0

這是相當困難的,從這個代碼得出任何真正結論,因爲它不是真的什麼。執行程序的內部隊列是瓶頸,這就是爲什麼您一次只能看到1個線程「工作」的原因。它並不真正起作用,它會從隊列中獲取下一個任務,使所有其他線程(也正在獲取下一個任務)等待。除了LinkedBlockingQueue.take()的功能之外,您並不真正在這裏測試任何東西。

increment()方法不是線程安全的,所以基本上你正在測試不好的代碼,結果幾乎不相關。如果您使CounterClient任務執行實際工作,需要幾毫秒,那麼與ForkJoinPool相比,您會發現性能差異較小(如果有)。

0

使用FixedThreadPool時,大部分時間都用於GarbageCollection,因爲程序會消耗大量的時間。我嘗試使用虛擬機參數-Xmx3g執行,並且在虛擬機嘗試避免內存不足時仍然卡在垃圾收集中。

您可能想要使用Memory Dump來深入瞭解消耗的根本原因,但我猜測它是計數器中的實例。

無論如何,根本原因似乎是FixedThreadPool使用的LinkedBlockingQueue工作隊列。由於for循環將100_000_000元素添加到workQueue,所以很少有另一個Thread實現從中獲取元素。因此,他們正在等待大部分時間,直到提交所有CounterClient s。

ForkJoinPool採用了更非阻塞方式,據我瞭解多工作隊列 S爲提交的行動。