我创建了一些工作流程,如何等待我创建的所有线程。此示例适用于99%的情况,但有时候方法waitForAllDone会在所有线程完成之前完成。我知道因为在waitForAllDone之后我正在关闭正在使用创建线程的流,因此发生异常
Caused by: java.io.IOException: Stream closed
我的主题开始于:
@Override
public void run() {
try {
process();
} finally {
Factory.close(this);
}
}
结束:
protected static void close(final Client client) {
clientCount--;
}
当我创建线程时,我称之为:
public RobWSClient getClient() {
clientCount++;
return new Client();
}
工厂内的和clientCount变量:
private static volatile int clientCount = 0;
等待:
public void waitForAllDone() {
try {
while (clientCount > 0) {
Thread.sleep(10);
}
} catch (InterruptedException e) {
LOG.error("Error", e);
}
}
答案 0 :(得分:5)
您需要通过clientCount
保护synchronized
的修改和阅读。主要问题是clientCount--
和clientCount++
不是原子操作,因此两个线程可以执行clientCount--
/ clientCount++
并最终得到错误的结果。
如上所述简单地使用volatile
只能在场上的所有操作都是原子的情况下才能工作。由于它们不是,您需要使用一些锁定机制。正如安东所说,AtomicInteger
在这里是一个很好的选择。请注意,它应该是final
或volatile
,以确保它不是线程本地的。
话虽如此,Java 1.5后的一般规则是使用ExecutorService
而不是Threads
。与Guava的Futures
类结合使用可以让所有人完成如下这样简单:
Future<List<?>> future = Futures.successfulAsList(myFutureList);
future.get();
// all processes are complete
答案 1 :(得分:3)
我不确定你的代码的其余部分是否有问题,但你不能像这样增加volatile变量 - clientCount++
;请改用AtomicInteger
答案 2 :(得分:1)
等待线程终止的最佳方法是使用其中一个高级并发工具。 在这种情况下,最简单的方法是使用ExecutorService。
您将以这种方式向执行者“提供”新任务:
...
ExecutorService executor = Executors.newFixedThreadPool(POOL_SIZE);
...
Client client = getClient(); //assuming Client implements runnable
executor.submit(client);
...
public void waitForAllDone() {
executor.awaitTermination(30, TimeUnit.SECOND) ; wait termination of all threads for 30 secs
...
}
通过这种方式,您不会在繁忙的等待或睡眠/唤醒周期中浪费宝贵的CPU周期。 有关详细信息,请参阅ExecutorService文档。