【问题标题】:Java reuse FixedThreadPool while waiting on main thread for a batch of work to completeJava在等待主线程完成一批工作时重用FixedThreadPool
【发布时间】:2018-02-07 13:21:24
【问题描述】:

我对 Java 多线程还很陌生,我找到了一些 responses 来做我想做的事情。然而,作为 java 线程的新手,我仍然很难跟踪响应。

基本上这就是我所拥有的:

private final ExecutorService mFixedThreadPool;

public ThreadPool(int threadCount) {
    mFixedThreadPool = Executors.newFixedThreadPool(threadCount);
}

public interface Task {
    void phase1();
    void phase2();
    void phase3();
}

public void executeBatch(List<Runnable> tasks) {
    tasks.forEach(task -> mFixedThreadPool.execute(task::phase1));
    tasks.forEach(task -> mFixedThreadPool.execute(task::phase2));
    tasks.forEach(task -> mFixedThreadPool.execute(task::phase3));
    //only return on the main thread once all the tasks are complete.
    //(Dont destroy threadpool as the "executeBatch" method will be called in a loop)
}

我想暂停或停止或等待调用“executeBatch”的线程,直到这批工作完成。我知道可以使用 mFixedThreadPool.shutdown() 执行此操作,然后等待其成功关闭,但是我想经常多次重用线程,因此每次关闭都是低效的。

【问题讨论】:

  • 我不明白。您已经链接到一个答案,该答案从字面上告诉您您需要做什么。这里有什么问题?
  • @Michael 我刚刚更新了代码,但基本上我已经阅读了我链接到的回复以及我可以找到的针对这个特定问题的其他一些回复,但我并没有真正明白Futures 集合的要点或我将如何实施该答案。就像“myRunnable”任务一样,我是否需要为每个任务都这样做,future.get() 是什么?应该做的,等等。
  • myRunnable 是一个Runnable,令人惊讶。就像您的task::phases 一样。 future 是运行可运行文件的结果。通过遍历所有期货,您正在等待所有提交的任务完成。请阅读这些类和方法的 JavaDocs。它们很容易找到。

标签: java multithreading parallel-processing


【解决方案1】:

如果您想要一个在前一个线程完成之前不会启动下一个线程的线程池,您可以简单地创建一个带有一个线程的 FixedThreadPool:

ExecutorService threadPool = Executors.newFixedThreadPool(1);

如果您想要的是让当前线程休眠,直到池完成使用关闭。 shutdown() 就是专门针对这种任务的,但是在关机之后你需要创建一个新的 ExecutorService:

threadPool.shutdown();
try {
  threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
  ...
}

您可以将 ExecutorService 封装在 ExecutorCompletionService 中。这将在完成时通知您,而不会像您想要的那样关闭 Executor。查看一些信息here

最后一个选项是使用 Future。 get() 方法会阻塞,直到该线程完成,因此您可以:

ExecutorService threadPool = Executors.newFixedThreadPool(4);
List<Callable<String>> tasks = new ArrayList<>();
List<Future<String>> futures = new ArrayList<>();
List<String> result = new ArrayList<>();
tasks.stream().forEachOrdered(task -> futures.add(threadPool.submit(task)));
for (Future<String> future :futures) {
    try {
        result.add(future.get());
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ExecutionException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }   
}

【讨论】:

  • 我想我的问题很清楚,我想要一个有 n 个线程的线程池,我可以将成批的任务排队。当这些任务并行执行时,主线程等待所有任务完成。有点像 for (int i = 0; i
  • 在这种情况下,我会使用关机。它可以防止向 ExecutorService 添加更多任务。如果您不希望这样,您可以使用 Future 选项,但如果稍后添加更多任务,您可能会遇到问题。
  • 任务批次定义得很好,不会在队列处理过程中添加,只是在处理之前/之后项目数量可能会增加或减少。您提到的可能问题在这种生命周期中是否仍然构成威胁?
  • 我仍然会选择使用 awaitTermination 的关机解决方案。它适用于所有情况,并且使用起来非常简单。另一种选择是将您的 ExecutorService 封装在 ExecutorCompletionService 中。
【解决方案2】:

我认为fork/join framework 可以给你你想要的。 您可以控制执行,并在需要时取消分叉任务并在主线程中计算。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-22
    • 2011-06-09
    • 1970-01-01
    • 2017-07-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多