【问题标题】:How to execute code after all the threads finished execution?在所有线程完成执行后如何执行代码?
【发布时间】:2022-01-10 12:52:35
【问题描述】:
private void processEvents(List<Object> events) {

        CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(
                () -> processEventsAsynchronously(events));
        while (!completableFuture.isDone() || completableFuture.isCancelled() || completableFuture.isCompletedExceptionally()) {
            // waiting for all threads to get processed
        }

        if (completableFuture.isDone() || completableFuture.isCancelled() || completableFuture.isCompletedExceptionally()) {
            executeRemainingFlow();
        }
    }

    private void processEventsAsynchronously(List<Object> events) {
        Executor executor = Executors.newFixedThreadPool(5);
        for (Object event : events) {
            Runnable runnable = () -> processEvent(event);
            executor.execute(runnable);
        }
    }

    private void processEvent(Object event) {
    
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void executeRemainingFlow() {

    }

在这里我想异步处理事件列表,一旦处理完成,我想实现剩余的流程。 我尝试使用 CompletableFuture,但执行器内部的代码在 executeRemainingFlow() 之后执行。

【问题讨论】:

  • 考虑使用 CountDownLatch
  • 在你运行CompletableFuture.runAsync的链上使用.whenComplete怎么样?
  • // waiting for all threads to get processed 代表什么?如果它代表 nothing(即,如果 processEvent() 除了等待之外什么都不做),那么 runAsync(...) 调用就没有意义了。您的程序异步执行某些任务 T 的唯一原因是如果您希望程序同时执行某些其他任务 U。如果在等待 T 完成时没有其他任务 U 可以执行,那么您最好调用执行任务 T 的函数,而不是异步运行它。
  • 嗨@SolomonSlow,这只是一个演示程序。在实际程序中,我必须返回成功处理事件和失败事件的计数,并获得该计数,我想等到 processEventsAsynchronously() 的执行完成
  • 是的,但是主线程在等待时会做什么else?您是否要将一些代码放入“等待所有线程得到处理”循环的主体中?我的意思是,如果您没有计划放入该循环的任何代码,则调用 runAsync(...) 没有任何意义。

标签: java multithreading java-8 java.util.concurrent


【解决方案1】:

首先,摆脱CompletableFuture.runAsync(...) 电话。它没有任何作用(请参阅上面关于您的问题的我的 cmets。)然后,使用 Executors.awaitTermination() 等待所有事件都被处理。剩下的就是:

private void processEvents(List<Object> events) {
    Executor executor = Executors.newFixedThreadPool(5);
    for (Object event : events) {
        Runnable runnable = () -> processEvent(event);
        executor.execute(runnable);
    }

    // Tell the `executor` to shut down _after_ all of the tasks have completed.
    executor.shutdown();

    // Wait until the executor has finished shutting down.
    try {
        executor.awaitTermination(9999, TimeUnit.DAYS);
    }
    catch (InterruptedException e) {
        System.err.println("Uh Oh! **THIS** should never have happened:");
        e.printStackTrace(System.err);
    }

    executeRemainingFlow();
}

【讨论】:

  • 感谢您的回答...还有一个问题...如果我多次调用 processEventsAsynchronously() 会怎样?我想在每个http请求上运行这个方法,因此它会创建多个执行器实例......这会导致任何内存问题
  • @AnkitKadam,如果程序要多次调用processEvents(),那么最好单独创建线程池,并将其作为参数传递给该函数。创建和销毁线程池不会导致“内存问题”,但这是一项代价高昂的操作,而且不需要多次。
猜你喜欢
  • 2015-03-25
  • 1970-01-01
  • 2021-08-10
  • 1970-01-01
  • 1970-01-01
  • 2013-10-23
  • 1970-01-01
  • 2012-02-08
  • 1970-01-01
相关资源
最近更新 更多