ExecutorService,如何在不阻塞主线程的情况下知道所有线程何时完成?

7

我有一个多线程实现,其中我创建了一个ExecutorService并提交要执行的任务,我想知道所有已提交的线程何时完成,而不会阻塞主线程和UI。我尝试过ExecutorService.awaitTermination(),但它会阻塞主线程和UI。我搜索了很多,但似乎找不到一种优雅的方法来做到这一点。我目前考虑创建另一个线程来计算完成的线程数量,并在它们全部完成时启动一个事件,但这似乎不是一个好的方法,我想要更好的解决方案!


你的主线程在做什么,以至于它不能被阻塞? - user207421
你使用的UI工具包是什么? - Dev
5个回答

7
使用SwingWorker关闭线程池并调用awaitTermination()。这将防止UI阻塞,并在您的SwingWorker实现上从事件分派线程调用done(),您可以使用它来触发任何所需的UI更改。
如果您希望通过UI更新跟踪正在运行的线程,则可以使用工作线程在循环中监视此操作,并使用参数调用publish(),然后将其传递到EDT上的process()实现。

1
他从未提到这是一个Swing应用程序,如果不是的话,那么SwingWorker就不合适。 - Hovercraft Full Of Eels
1
我忘了提到它是一个Swing应用程序! - Trota
在更多地了解SwingWorker之后,我意识到这是一个相当简单的解决方案来解决我的问题!谢谢开发者! - Trota
好家伙,我错了。1+。还有@user1220585:这是非常重要的信息,应该在原始帖子中提到。 - Hovercraft Full Of Eels

4
为什么不使用 CountDownLatch,当计数器完成后通知主线程?

1
好主意;这里引用了一个不错的例子(https://dev59.com/3VDTa4cB1Zd3GeqPGRYV#3588523)。 - trashgod
1
@trashgod 刚刚在您的帖子中发表了评论:示例在访问 EDT 的 textComponent 时存在小故障。 - kleopatra

2
您可以维护一个单独的线程来跟踪执行器服务实例何时关闭:
    final ExecutorService execSvc = ...;
    execSvc.submit(task1);
    ...
    execSvc.submit(taskN);
    // important to request the exec service to shut down :)
    execSvc.shutdown();

    new Thread(new Runnable() {

        public void run() {
            while (!execSvc.isTerminated()) {
                try {
                    execSvc.awaitTermination(60, TimeUnit.SECONDS);
                } catch (InterruptedException e) {
                    // ignore exception
                }
            }
            System.out.println("ExecSvc.run: exec service has terminated!");
            // possibly submit a task using SwingUtilities.invokeLater() to update the UI
        }

    }).start();

2
使用CountDownLatch CountDownLatch latch = new CountDownLatch(totalNumberOfTasks); ExecutorService taskExecutor = Executors.newFixedThreadPool(4); while(...) { taskExecutor.execute(new MyTask()); }
try { latch.await(); } catch (InterruptedException E) { // 处理异常 } 并在您的任务中(用try / finally括起来)
 latch.countDown();
在ExecutorService上,您可以调用shutdown(),然后再调用awaitTermination()。
例如: ``` ExecutorService taskExecutor = Executors.newFixedThreadPool(4); while(...) { taskExecutor.execute(new MyTask()); } taskExecutor.shutdown(); try { taskExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } catch (InterruptedException e) { ... } ```
同时,还可以查看此答案

1
除非我对理解有误,否则这两个解决方案都没有解决 OP 的根本问题,即避免在主线程上阻塞。 - Trevor

2

isTerminated() 方法就可以了。

但是需要注意的是,只有在调用 shutdown 方法后,awaitTerminationisTerminated 才会给出有意义的结果。


我已经了解了isTerminated()的一些内容,但我认为我需要在“侧线程”上运行它来不断检查它是否返回true,这就带我回到了最初的解决方案! - Trota

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接