限制Java線程池運行線程以及等待線程數量的策略
限制Java線程池運行線程以及等待線程數量的策略
對于 java.util.concurrent.Executors 所提供的 FixedThreadPool ,可以保證可以在內存中有固定數量的線程數運行。但是由于 FixedThreadPool 綁定的是 LinkedBlockingQueue 。隊列的上限沒有限制(默認上限為 Integer.MAX_VALUE ),不斷的提交新的線程,會造成任務在內存中長時間的堆積。
我們有可能面臨如下的場景,主線程不斷地提交任務線程,希望有固定數量的在線程中運行,也不想造成線程在內存中大量的等待堆積。由此需要我們自己定義一個線程池策略。 ThreadPoolExecutor 為我們線程池的設置提供了很大的靈活性。
首先看 FixedThreadPool 的實現:
public static ExecutorService More ...newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
可以看到,FixedThreadPool綁定的是 LinkedBlockingQueue<Runnable> 。我們需要做的第一個改造就是綁定有大小上線的BlockingQueue,在我的實現中綁定 ArrayBlockingQueue<Runnable> 并設置了size。
第二個是采用CallerRunsPolicy。ThreadPoolExecutor可以定義不同的任務拒絕策略。CallerRunsPolicy指的是當線程池拒絕該任務的時候,線程在本地線程直接 execute 。這樣就限制了本地線程的循環提交流程。
BlockingQueue<Runnable> workingQueue = new ArrayBlockingQueue<Runnable>(10);
RejectedExecutionHandler rejectedExecutionHandler =
new ThreadPoolExecutor.CallerRunsPolicy();
ExecutorService threadPool = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS,
workingQueue, rejectedExecutionHandler);
for (int i = 0; i < 100; i++) {
threadPool.submit(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
System.out.println("thread " + String.valueOf(threadNo) + " is called");
Thread.sleep(10000);
System.out.println("thread " + String.valueOf(threadNo) + " is awake");
throw new Exception();
}
});
}</code></pre>
代碼中定義了大小為10的線程池,for循環提交了20個線程的時候,10個執行線程,10個線程放入了 workingQueue 。當提交到第21個線程的時候,會觸發RejectedExecutionHandler。在這里我們配置了CallerRunsPolicy策略。所以會在主線程直接執行該線程。也就是說,在本程序中最多會有11個線程在執行,10個線程在等待。由此限制了線程池的等待線程數與執行線程數
來自: https://segmentfault.com/a/1190000005876711