2017-02-16 33 views
3

要檢查我已經寫的代碼主題:如何檢查池「重用」主題

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++) { 
      executorService.submit(new Runnable() { 
       @Override 
       public void run() { 
        try { 
         threads.add(Thread.currentThread()); 
         atomicLong.incrementAndGet(); 
         countDownLatch.countDown(); 
        } catch (Exception e) { 
         System.out.println(e); 
        } 


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

正如你可以看到我用HashSet<Thread>

它的用法是正確的只有螺紋不變。至少在測試中。

據我所知equals/hashCode沒有被覆蓋,因此從Object繼承。

因此,請回答如果我的測試不正確,哪裏出錯。
如果你知道更聰明的方式,請分享一下。

+0

你能解釋進一步你遇到什麼問題?你的代碼在我的項目中運行良好。 – Henrik

+0

@Henrik我不確定我是否正確地調整了線程輪詢「重用」線程的方式 – gstackoverflow

+0

我會爭辯說,您的代碼實際上設法驗證test()是使用它們創建100個線程並執行500個小任務。如果情況不是這樣,你的'RunTimeException'將被拋出。你正在尋找更短的方式來證明這一點? – Henrik

回答

2

正如我在評論中提到的,我會爭辯說,你的代碼實際上設法驗證test()創建100個線程並使用它們執行500個小任務。如果不是這樣,你的斷言肯定會觸發。

驗證此問題的另一種方法是使用ThreadLocal來計算實際運行的線程數。

我創建了以下單元測試,它使用ThreadLocal來計算由Executor創建的線程數。嘗試研究其輸出以確信所創建線程的數量。

@Test 
public void threadCounter() throws Throwable { 
    ThreadLocal<Integer> number = new ThreadLocal<Integer>() { 
     private final AtomicInteger values = new AtomicInteger(); 

     @Override 
     protected Integer initialValue() { 
      return values.getAndIncrement(); 
     } 
    }; 

    ExecutorService threadPool = Executors.newFixedThreadPool(100); 

    for (int i = 0 ; i < 500 ; i++) { 
     final int count = i; 
     threadPool.submit(() -> System.out.printf("%-4s : %-20s - %s\n", count, Thread.currentThread().getName(), number.get())); 
    } 

    threadPool.shutdown(); 
    threadPool.awaitTermination(10, TimeUnit.SECONDS); 

    Assert.assertEquals(100, number.get().intValue()); 

} 
+0

我沒有junit在手邊。通過閱讀我不明白你在哪裏incrent threadLocal第一次之後 – gstackoverflow

+0

另外我覺得名字可以重用。如果第一個線程死了 - 第二個線程已經使用了這個名字 – gstackoverflow

+0

將代碼複製到「main」方法以獲得相同效果。每當新線程第一次訪問'number'時,就會調用'ThreadLocal'實例的'initialValue'。這會導致'號碼'增加。 – Henrik

1

我不知道,我已瞭解如何正確線程[池]「重複使用」線程。

池線程(也叫做工作線程)具有run()方法,就像任何其他的線程,而這也正是「再利用」發生。基本上,工作線程的run()方法挑選從隊列任務(即客戶端提供Runnable對象),並運行它們:

class ReallySimplePoolWorker { 

    public ReallySimplePoolWorker(BlockingQueue<Runnable> workQueue) { 
     this->workQueue = workQueue; 
    } 

    public void Run() { 
     while (...not shutting down...) { 
      Runnable task = workQueue.take(); 
      try { 
       task.run(); 
      } catch (Exception ex) { 
       ...notify the pool object of the exception... 
      } 
     } 
    } 

    private final BlockingQueue<Runnable> workQueue; 
}