如何从多个线程中获取第一个结果并取消剩余 [英] How to get the first result from multiple threads and cancel remaining

查看:31
本文介绍了如何从多个线程中获取第一个结果并取消剩余的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有请求和多个线程,它们以不同的方式寻找结果,每个线程都应该在某个时候得到一些结果..我需要接受第一个完成的线程的结果,返回这个结果并杀死所有剩余的线程.当我返回一些默认结果时,我也有超时..

I have request and multiple threads, which are looking for result in different ways and each thread should get some result at some point.. I need to take the result from the first finished thread, return this result and kill all of the remaining threads. I also have timeout when I'll return some default result..

我能想到两个解决方案,但对我来说,没有一个是正确的"..

I can think of two solutions, none of which seems "correct" to me..

1) 遍历任务,询问是否完成,睡一会并返回它找到的第一个完成的任务..

1) Loop through the tasks, ask if they are finished, sleep for a while and return the first finished task it founds..

import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import org.apache.log4j.LogManager;

public class App {    
    public static final ExecutorService executors = Executors.newCachedThreadPool();

    public static void main(String[] args) {
        ArrayList<Future<String>> taskList = new ArrayList<>();
        taskList.add(executors.submit(new Task1()));
        taskList.add(executors.submit(new Task2()));

        String result = null;
        long start = System.currentTimeMillis();
        long timeout = 1000;

        while ((start + timeout) < System.currentTimeMillis()) {
            try {
                for (Future<String> future : taskList) {
                    if (future.isDone()) {
                        result = future.get();
                        break;
                    }
                }

                if (result != null) {
                    break;
                }

                Thread.sleep(10);
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }

        if (result == null) {
            result = "default..";
        }
    }

}

class Task1 implements Callable<String> {
    @Override
    public String call() throws Exception {
        // find result in one way
        return new String("result..");
    }
}

class Task2 implements Callable<String> {
    @Override
    public String call() throws Exception {
        // find result in some other way
        return new String("result..");
    }
}

2) 通过调用future.get(timeout, TimeUnit.MILLISECONDS); 用另一个线程监视每个任务,然后第一个完成的线程将调用future.cancel(true); 用于所有其他线程...

2) Monitor each task with another thread by calling future.get(timeout, TimeUnit.MILLISECONDS); and the first finished thread would then call future.cancel(true); for all other threads...

第一个解决方案在我看来像是浪费处理器时间,第二个在我看来像是浪费线程..

The first solution seems to me like wasting processor time, and the second seems to me like wasting threads..

最后,问题是:有没有更好的解决方案?

Finally, the Question is: Is there any better solution?

提前致谢

谢谢大家的回答,我已经使用John H"的回答解决了这个问题:

Thank you all for answers, I have solved this using "John H" 's answer:

有一个内置函数可以执行此操作:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#invokeAny%28java.util.Collection,%20long,%20java.util.concurrent.TimeUnit%29

There is a built in function that does this: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#invokeAny%28java.util.Collection,%20long,%20java.util.concurrent.TimeUnit%29

这将调用您给它的所有任务,并等待第一个返回答案,直到时间限制.如果它们都没有及时返回结果,您可以捕获 TimeoutException 并返回默认值.否则,您可以使用它返回的第一个值,它会负责取消其余的任务.

This will invoke all the tasks you give it, and wait for the first one to return an answer up to a time limit. If none of them return a result in time you can catch the TimeoutException and return the default value. Otherwise you can use the first value it returns and it will take care of cancelling the rest of the tasks.

推荐答案

有一个内置函数可以做到这一点:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#invokeAny%28java.util.Collection,%20long,%20java.util.concurrent.TimeUnit%29

There is a built in function that does this: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#invokeAny%28java.util.Collection,%20long,%20java.util.concurrent.TimeUnit%29

这将调用你给它的所有任务,并等待第一个任务返回一个时间限制.如果它们都没有及时返回结果,您可以捕获 TimeoutException 并返回默认值.否则,您可以使用它返回的第一个值,它会负责取消其余的任务.

This will invoke all the tasks you give it, and wait for the first one to return an answer up to a time limit. If none of them return a result in time you can catch the TimeoutException and return the default value. Otherwise you can use the first value it returns and it will take care of cancelling the rest of the tasks.

这篇关于如何从多个线程中获取第一个结果并取消剩余的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆