2012-01-05 67 views
2

我使用ThreadPoolExecutor来管理线程池。我们想要的是:如何保持核心线程存活并消除ThreadPoolExecutor中多余的线程? keepAliveTime不能按预期工作

  1. 如果该池的corePoolSize线程少于某个新任务,则启动一个新线程;
  2. 如果池的corePoolSize线程多且全部忙,则启动新任务的新线程,直到达到maxPoolSize。在这种情况下,拒绝任务;
  3. 保持线程corePoolSize数活着,即使他们空转,多余的线程将死,如果他们已经闲置超过KeepAliveTime的

根据文档的Java6,KeepAliveTime的应该按上述方式工作。但在我的测试代码中,它并不一致。

当我将keepAliveTime设置为0时,它工作正常,始终保持核心线程活动并在完成时终止多余的线程;
但是,如下所示,当我将keepAliveTime设置为正值时,它似乎终止了所有空闲线程,无论它们是否为核心线程。

ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 500, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>()); 
assertFalse("Not allow core threads to time out.", executor.allowsCoreThreadTimeOut()); 
Task task_1 = new Task(1000); 
Task task_2 = new Task(1000); 
Task task_3 = new Task(1000); 
executor.execute(task_1); 
executor.execute(task_2); 
executor.execute(task_3); 
Thread.sleep(1050L); 
assertEquals("Completed 3 tasks.", 3, executor.getCompletedTaskCount()); 
assertEquals("Three threads are in the pool.", 3, executor.getPoolSize()); 
Thread.sleep(600L); 
//////// This assertion will fail: **expected <2> but was <0>** 
assertEquals("Two threads are in the pool.", 2, executor.getPoolSize()); 

////---- 
private static class Task implements Runnable { 
    private long sleepMillis; 
    public Task(final long sleepMillis) { 
     this.sleepMillis = sleepMillis; 
    } 
    public void run() { 
     try { Thread.sleep(sleepMillis); 
     } catch (Exception e) { System.out.println(e); } 
    } 
} 

对keepAliveTime或getPoolSize有任何误解吗?如果getPoolSize不是正确的API,我怎样才能知道“活动”线程的数量(空闲或忙碌)?

在此先感谢。

+0

有些事情需要考虑:keepAlive是从创建线程还是没有更多任务要执行时开始倒计时? – LazyCubicleMonkey 2012-01-05 08:41:31

+0

@LazyCubicleMonkey我认为它应该是后者。在[setKeepAliveTime](http://enos.itcollege.ee/~jpoial/docs/api/java/util/concurrent/ThreadPoolExecutor.html#setKeepAliveTime%28long,%20java.util.concurrent.TimeUnit%29)中,它定义“时间”作为执行任务**之后等待**的时间。无论哪种方式,如果不允许coreThreadTimeOut,它不应该应用于核心线程。 – arosima 2012-01-08 22:42:25

回答

1

Java 7通过测试。显然,Java 6有一个错误。读取它的代码,所有线程都可以在队列为空时退出,这对于核心线程来说肯定是错误的。

+0

是的,我同意。我也检查了源代码。每个工作人员在完成其任务后从池中删除自己,而不检查池中有多少线程仍处于活动状态。但后来我变得更加困惑:当我将keepAliveTime设置为0时,似乎核心线程确实保存在池中。它是如何工作的? – arosima 2012-01-09 01:39:40

0

我很确定游泳池的大小是一个目标大小。我不认为有关于关闭线程的任何保证(没有背景检查器)我认为它只是一个提示。空闲线程几乎没有开销。

+1

从Java 6的源代码中,每个工作人员将从池中删除自己,并在完成任务后减小poolSize。在我看来,poolSize更像是activeCount而不是threadCount。 – arosima 2012-01-09 01:44:08

1

@arosima keepAliveTime仅对超出的线程而不是核心线程生效。核心线程将始终保存在池中。我也写了another answer了解,希望对大家有帮助。