简体   繁体   English

ExecutorService 由多个线程执行单个任务 n 次(n 个线程“竞争”)

[英]ExecutorService to execute a single task n times by multiple threads (n thread “races”)

I need to execute a single task by multiple threads, such that when the first thread finishes and before any other thread finishes, all the threads are stopped and start the same task all over again.我需要由多个线程执行单个任务,这样当第一个线程完成并且在任何其他线程完成之前,所有线程都将停止并重新开始相同的任务。 This should be performed n times.这应该执行n次。

My attempt is using Callable<V> and the method invokeAny() (that is why I use the set) but not sure how to accomplish the goal.我的尝试是使用Callable<V>和方法invokeAny() (这就是我使用集合的原因)但不确定如何实现目标。

ExecutorService executor = Executors.newFixedThreadPool(10);
Callable<String> task = () -> {
    someTask();
    return "";
};
Set<Callable<String>> tasks = new HashSet<>();
IntStream.range(0, n).forEach(i -> {
    tasks.add(task);
    executor.submit(task);
});

How to finish this?如何完成这个? or any better solution?或任何更好的解决方案?

Here's one suggestion:这是一个建议:

class Task implements Callable<Integer> {

    private final static Random RND = new Random();

    @Override
    public Integer call() throws Exception {
        try {
            // Work on task for a random duration
            Thread.sleep(RND.nextInt(5000));
        } catch (InterruptedException e) {
            System.err.println("I was interrupted."
                    + "Someone else probably solved the task before me.");
            return -1;
        }

        // Return some dummy value
        return RND.nextInt();
    }
}

class Scratch {
    public static void main(String[] args) throws InterruptedException {

        final int numWorkers = 3; // number of tasks to run in parallel

        ExecutorService executor = Executors.newFixedThreadPool(numWorkers);

        // Solve task 5 times. (Change it to while (true) { ...} if you like.)
        for (int i = 0; i < 5; i++) {

            CompletionService<Integer> completionService =
                    new ExecutorCompletionService<>(executor);

            Future<?>[] futures = new Future<?>[numWorkers];
            for (int j = 0; j < numWorkers; j++) {
                futures[j] = completionService.submit(new Task());
            }

            Future<Integer> firstToComplete = completionService.take();

            try {
                Integer result = firstToComplete.get();
                System.err.println("We got a result: " + result);
            } catch (ExecutionException e) {
                // Should not happen. Future has completed.
            }

            // Cancel all futures (it doesn't matter that we're cancelling
            // the one that has already completed).
            for (int j = 0; j < numWorkers; j++) {
                futures[j].cancel(true);
            }
        }

        executor.shutdown();
    }
}

If the task you're solving does not respond to interrupts, passing true to cancel(...) won't help.如果您正在解决的任务不响应中断,则将true传递给cancel(...)将无济于事。 In that case I'd suggest you do the following changes:在这种情况下,我建议您进行以下更改:

  1. Create an AtomicBoolean done variable in the outer for loop.在外部for循环中创建一个AtomicBoolean done变量。
  2. Pass this to the constructor to Task and save it in a field in Task .将其传递给Task的构造函数并将其保存在Task的字段中。
  3. In the task solving process, check done flag ever so often, and cancel the attempt if done is true .在任务解决过程中,经常检查done标志,如果donetrue则取消尝试。
  4. Instead of calling cancel on the tasks after the first result is in, set done to true and wait for the other threads to return.不要在第一个结果出现后对任务调用cancel ,而是将done设置为true并等待其他线程返回。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM