2015-11-17 100 views
5

我想創建一個緩存線程池,但它作爲一個固定的線程池。目前,我有這樣的代碼:線程池不調整大小

public class BackgroundProcesses { 

    public static void main(String[] args) throws InterruptedException, ExecutionException { 
     //ExecutorService threadPool2 = Executors.newCachedThreadPool(); 
     ExecutorService threadPool = new ThreadPoolExecutor(2, 10, 180, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); 
     for (int i = 0; i < 800; i++) { 
      Callable<String> task = new Task(); 
      threadPool.submit(task); 
     } 
    } 
} 

class Task implements Callable<String> { 

    @Override 
    public String call() throws Exception { 
     Thread.sleep(100); 
     System.out.println(Thread.currentThread().getName() + " is ready"); 
     return ""; 
    } 
} 

如果我運行代碼,我得到的輸出:

pool-1-thread-1 is ready 
pool-1-thread-2 is ready 
pool-1-thread-1 is ready 
pool-1-thread-2 is ready 
... 

含義只有2個線程正在做的各項工作,並沒有新的工作線程被添加到池中。如果任務在隊列中等待(最多10個),線程池不應該產生更多的線程?

我不想使用Executors.newCachedThreadPool(),因爲它實際上沒有最大線程的上限,它有corePoolSize 0。我希望有一些線程隨時準備好以提高響應能力。

-----編輯1 -----

謝謝你阿列克謝的答案。將容量設置爲隊列使其表現得如預期的那樣,但是現在我遇到了一個新問題。

後臺任務的數量差別很大。大部分時間爲0,但在短時間內最多可以執行50個併發任務。什麼是處理這個問題的有效方法?請記住,大多數後臺任務都是短暫的(< 1秒),但也有一些長期任務(> 1分鐘)。

如果我把我的線程池像這樣:

ExecutorService threadPool = new ThreadPoolExecutor(2, 10, 180, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10)); 

我將最有可能與峯值使用得到RejectedExecutionException。但是,如果我設置線程池像這樣:

ExecutorService threadPool = new ThreadPoolExecutor(2, 10, 180, TimeUnit.SECONDS, new LinkedBlockingQueue<>(200)); 

,則任何新的工作線程將永遠不會加入,因爲隊列不會最大程度的發揮。

CPU至少有4個內核,所以這在我看來是浪費。大多數情況下,根本沒有任何後臺任務(80%的正常運行時間),因此保留固定的線程池也是浪費的。

回答

4

ThreadPoolExecutor的Javadoc說:

當一個新的任務在方法提交執行(Runnable接口),以及 比corePoolSize線程較少的運行,一個新的線程創建 處理請求,即使其他工作線程閒置。只有當隊列如果 比corePoolSize大於maximumPoolSize線程 運行,一個新的線程將被創造了更多的卻少全

LinkedBlockingQueue從來都不是滿的,因爲它沒有對數量上限的元素。將new LinkedBlockingQueue()改爲new LinkedBlockingQueue(10)可以解決這個問題。

+0

感謝您的理解。但是現在我得到了RejectedExecutionException(池大小= 10,活動線程= 10,排隊任務= 10),因爲隊列被填滿並且所有活動的線程都用完了。 –