【发布时间】:2016-05-27 11:15:54
【问题描述】:
我有请求和多个线程,它们以不同的方式寻找结果,每个线程都应该在某个时候得到一些结果。我需要采取 第一个完成的线程的结果,返回此结果并杀死所有剩余线程。当我返回一些默认结果时,我也有超时..
我能想到两种解决方案,但在我看来,没有一个是“正确的”..
1) 遍历任务,询问是否完成,休眠一会,返回找到的第一个完成的任务..
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);...
第一个解决方案在我看来是浪费处理器时间,第二个在我看来是浪费线程..
最后,问题是:有没有更好的解决方案?
提前谢谢你
编辑:谢谢大家的回答,我已经用“John H”的回答解决了这个问题:
这将调用你给它的所有任务,并等待第一个返回答案直到时间限制。如果它们都没有及时返回结果,您可以捕获 TimeoutException 并返回默认值。否则,您可以使用它返回的第一个值,它将负责取消其余任务。
【问题讨论】:
-
不要使用
new String("result");创建String。 -
使用 CompletionService:When should I use a CompletionService over an ExecutorService?
标签: java multithreading