如何确保线程池完成?

时间:2011-09-08 19:43:13

标签: java synchronization threadpool runnable

设置:

我正在改变程序在幕后工作的方式。在当前版本中的工作方式如下:

public void threadWork( List<MyCallable> workQueue )
{
    ExecutorService pool = Executors.newFixedThreadPool(someConst);
    List<Future<myOutput>> returnValues = new ArrayList<Future<myOutput>>();
    List<myOutput> finishedStuff = new ArrayList<myOutput>();

    for( int i = 0; i < workQueue.size(); i++ )
    {
        returnValues.add( pool.submit( workQueue.get(i) ) );
    }

    while( !returnValues.isEmpty() )
    {
        try
        {
            // Future.get() waits for a value from the callable
            finishedStuff.add( returnValues.remove(0).get(0) );
        }
        catch(Throwable iknowthisisbaditisjustanexample){}
    }

    doLotsOfThings(finsihedStuff);
}

但是新系统将使用私有内部Runnable来调用将数据写入全局变量的synchronized方法。我的基本设置是:

public void threadReports( List<String> workQueue )
{
    ExecutorService pool = Executors.newFixedThreadPool(someConst); 
    List<MyRunnable> runnables = new ArrayList<MyRunnable>()

    for ( int i = 0; i < modules.size(); i++ )
    {
        runnables.add( new MyRunnable( workQueue.get(i) );
        pool.submit(threads.get(i));
    }

    while( !runnables.isEmpty() )
    {
        try 
        {
            runnables.remove(0).wait(); // I realized that this wouldn't work
        } 
        catch(Throwable iknowthisisbaditisjustanexample){}
    }
    doLotsOfThings(finsihedStuff); // finishedStuff is the global the Runnables write to
}

如果您在尝试第二段代码时阅读我的​​评论,您会注意到我不知道如何使用wait()。我原以为它基本上就像thread.join()但是在看完文档后我发现它不是。

我可以根据需要更改某些结构,但是使用runnables,让runnables写入全局变量以及使用线程池的基本系统是需求。


问题

在doLotsOfThings()之前,如何等待线程池完全完成?

5 个答案:

答案 0 :(得分:2)

您应该致电ExecutorService.shutdown(),然后致电ExecutorService.awaitTermination

...
pool.shutdown();
if (pool.awaitTermination(<long>,<TimeUnit>)) {
    // finished before timeout
    doLotsOfThings(finsihedStuff);
} else {
    // Timeout occured.
}

答案 1 :(得分:2)

试试这个:

pool.shutdown();
pool.awaitTermination(WHATEVER_TIMEOUT, TimeUnit.SECONDS);

答案 2 :(得分:1)

public void threadReports( List<String> workQueue )
{
    ExecutorService pool = Executors.newFixedThreadPool(someConst); 
    Set<Future<?>> futures = new HashSet<Future<?>>();

    for ( int i = 0; i < modules.size(); i++ )
    {
        futures.add(pool.submit(threads.get(i)));
    }

    while( !futures.isEmpty() )
    {
        Set<Future<?>> removed = new Set<Future<?>>();
        for(Future<?> f : futures) {
            f.get(100, TimeUnit.MILLISECONDS);
            if(f.isDone()) removed.add(f);
        }
        for(Future<?> f : removed) futures.remove(f);
    }
    doLotsOfThings(finsihedStuff); // finishedStuff is the global the Runnables write to
}

答案 3 :(得分:1)

您是否考虑过使用现在包含在Java 7中的Fork/Join框架。如果您还不想使用Java 7,则可以获取它的jar here

答案 4 :(得分:1)

shutdownExecutorService的生命周期方法,并在调用后使执行程序无法使用。在方法中创建和销毁ThreadPools与创建/销毁线程一样糟糕:它几乎违背了使用线程池的目的,即通过启用透明重用来减少线程创建的开销。

如果可能,您应该将ExecutorService生命周期与应用程序保持同步。 - 首次需要时创建,在应用关闭时关闭。

为了实现执行大量任务并等待它们的目标,ExecutorService提供方法invokeAll(Collection<? extends Callable<T>> tasks)(如果要等待特定时间段,则提供带超时的版本。)

使用此方法和上述一些要点,相关代码变为:

public void threadReports( List<String> workQueue ) {

    List<MyRunnable> runnables = new ArrayList<MyRunnable>(workQueue.size());
    for (String work:workQueue) {
        runnables.add(new MyRunnable(work));
    }
    // Executor is obtained from some applicationContext that takes care of lifecycle mgnt
    // invokeAll(...) will block and return when all callables are executed 
    List<Future<MyRunnable>> results = applicationContext.getExecutor().invokeAll(runnables); 

    // I wouldn't use a global variable unless you have a VERY GOOD reason for that.  
    // b/c all the threads of the pool doing work will be contending for the lock on that variable.
    // doLotsOfThings(finishedStuff);  

    // Note that the List of Futures holds the individual results of each execution. 
    // That said, the preferred way to harvest your results would be:
    doLotsOfThings(results);
}

PS:不确定为什么threadReportsvoid。它可以/应该返回doLotsOfThings的计算以实现更实用的设计。