【问题标题】:Executing two tasks consecutively连续执行两个任务
【发布时间】:2016-07-27 10:33:31
【问题描述】:

有一个带有单个线程的线程池,用于执行由多个线程提交的任务。该任务实际上由两部分组成 - perform 具有有意义的结果,cleanup 需要相当长的时间但没有返回有意义的结果。目前(显然不正确)实现看起来像这样。有没有一种优雅的方法来确保另一个perform 任务仅在前一个cleanup 任务之后执行?

public class Main {
    private static class Worker {
        int perform() {
            return 1;
        }

        void cleanup() {
        }
    }

    private static void perform() throws InterruptedException, ExecutionException {
        ExecutorService pool = Executors.newFixedThreadPool(1);
        Worker w = new Worker();
        Future f = pool.submit(() -> w.perform());
        pool.submit(w::cleanup);
        int x = (int) f.get();
        System.out.println(x);
    }
}

【问题讨论】:

  • 按正确的方式提交不应该是这样吗?例如,执行、清理、执行、清理。
  • 为什么不只是pool.submit(() -> { w.cleanup(); return w.perform(); });
  • @СӏаџԁеМаятіи 这可能会不必要地延迟perform()。想象一下cleanup() 需要一分钟,perform() 需要一秒钟,我们每两分钟提交一个任务。
  • 但是你的池只有一个线程。它们不会同时运行。所以这就是重点?

标签: java multithreading


【解决方案1】:

有没有一种优雅的方法来确保另一个执行任务仅在前一个清理任务之后执行?

最明显的做法是从perform() 调用cleanup(),但我认为您不这样做是有原因的。

您说您的解决方案目前“明显不正确”。为什么?因为比赛条件?然后你可以添加一个synchronized 块:

synchronized (pool) {
    Future f = pool.submit(() -> w.perform());
    pool.submit(w::cleanup);
}

这将确保cleanup() 将紧跟在perform() 之后。如果您担心synchronized 会影响性能,请不要担心。

另一种解决方案可能是使用ExecutorCompletionService class,尽管我不确定这对一个线程有何帮助。我之前在另一个线程池中运行清理任务时使用过它。

【讨论】:

    【解决方案2】:

    如果您使用的是 java8,则可以使用 CompletableFuture 进行此操作

    CompletableFuture.supplyAsync(() -> w.perform(), pool)
        .thenApplyAsync(() -> w.cleanup(), pool)
        .join();
    

    【讨论】:

    • 在这种情况下,您确定在执行和清理之间不会执行任何任务吗?
    猜你喜欢
    • 1970-01-01
    • 2013-02-13
    • 1970-01-01
    • 1970-01-01
    • 2017-05-03
    • 1970-01-01
    • 2021-11-16
    • 2020-06-08
    • 1970-01-01
    相关资源
    最近更新 更多