2012-11-20 233 views
0

我创建了一些工作流如何等待我创建的所有线程。这个例子在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

查看java中的信号量文档。该示例几乎相同,您需要:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html –

回答

5

你需要通过​​保障clientCount修改和阅读。主要问题是clientCount--clientCount++不是原子操作,因此两个线程可能执行clientCount--/clientCount++并最终得到错误的结果。

只要使用volatile,如上所述,只有在该字段上的所有操作都是原子的情况下才会工作。由于它们不是,你需要使用一些锁定机制。正如安东所说,AtomicInteger是一个很好的选择。请注意,它应该是finalvolatile以确保它不是线程本地的。

也就是说,Java 1.5的一般规则是使用ExecutorService而不是Threads。与番石榴的Futures类可以让等待所有一起选择使用这个完成是简单的:

Future<List<?>> future = Futures.successfulAsList(myFutureList); 
future.get(); 
// all processes are complete 

Futures.successfulAsList

+0

但我只有一个线程正在创建其他线程。那么还有谁能够增加这个价值呢? – hudi

+0

只要您采取了适当的保护措施,就可以从任意数量的线程增加值。 –

+0

好吧,有没有选择如何测试它? – hudi

3

我不知道你的你的代码的其余部分没有问题,但你不能像这样增加volatile变量 - clientCount++;使用AtomicInteger而不是

+0

为什么我不能增加它。你能发表一些文件吗? – hudi

+0

导致它不是原子操作。在A = A + 1的A值可能已被另一个线程更改 – Anton

+4

@ hudi考虑从亚马逊订购http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601 - 几乎不可能用试错法编写一个线程安全的代码 –

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文档。