2015-11-17 69 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),因为队列被填满并且所有活动的线程都用完了。 –