0

我试图运行ExecutorService对象,FixedThreadPool但遇到了问题。

我希望程序能在纳秒内运行,但它被挂起。我发现我需要Semaphore和它一起使用,这样队列中的项目就不会被累加。

有什么方法可以让我知道池中的所有线程都已使用。

基本代码...

static ExecutorService pool = Executors.newFixedThreadPool(4);
static Semaphore permits = new Semaphore(4);
try {
    permits.acquire();
    pool.execute(p);  // Assuming p is runnable on large number of objects
    permits.release();
} catch ( InterruptedException ex ) {
}

这段代码被挂起,我真的不知道为什么。如何知道池当前是否正在等待所有线程完成?

4

3 回答 3

3

默认情况下,如果您向池中提交超过 4 个任务,则额外的任务将排队,直到有线程可用。

您在评论中引用的博客使用信号量来限制一次可以排队的工作量,这对您来说不是问题,直到您有数千个任务排队并且它们开始占用可用内存。无论如何,有一种更简单的方法可以做到这一点 - 构造一个带有有界队列的ThreadPoolExecutor 。*但这不是你的问题。

如果您想知道任务何时完成,请注意ExecutorService.submit()返回一个Future可用于等待任务完成的对象:

Future<?> f = pool.execute(p);
f.get();
System.out.println("task complete");

如果您有多个任务并希望等待所有任务完成,请将每个任务存储 Future在一个列表中,然后依次调用get()每个任务,或者进行调查ExecutorService.invokeAll()(本质上是相同的,但在单个方法调用中)。

您还可以判断任务是否已完成:

Future<?> f = pool.execute(p);

while(!f.isDone()) {
    // do something else, task not complete
}

f.get();

最后,请注意,即使您的任务完成,如果您没有调用shutdown()线程池,您的程序也可能不会退出(因此看起来“挂起”);原因是线程仍在运行,等待被赋予更多的工作去做。

*编辑:抱歉,我刚刚重新阅读了我的答案并意识到这部分是不正确的 - ThreadPoolExecutor向队列 提供任务并在它们不被接受时拒绝它们,因此有界队列与信号量方法具有不同的语义。

于 2010-11-13T21:20:19.860 回答
1

您不需要信号量。

如果您挂起,可能是因为线程将自己锁定在其他地方。

在调试器中运行代码,当它挂起时暂停它,看看线程在做什么。

于 2010-11-13T19:59:30.007 回答
0

您可以更改为使用ThreadPoolExecutor。它包含一个getActiveCount()返回活动线程的近似计数的方法。为什么它是近似值我不确定。

于 2010-11-13T20:03:12.097 回答