我引用this link来创建固定大小的线程池。然后我有一个允许提交Callable
请求并获得结果的方法,它看起来像这样:
private ExecutorService threadPool = Executors.newFixedThreadPool(5);
private CompletionService<String> pool = new ExecutorCompletionService<String>(threadPool);
public void execute(Callable<String> request){
pool.submit(request);
// what happen if this method is called before get the result???
try {
String result = pool.take().get();
System.out.println("result is " + result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
可以多次调用此execute方法,并且请求具有不同的执行时间。问题是我想在完成后立即获得结果。我想确保在执行此方法时,可以处理其他调用并允许添加线程轮询。
以下是一个示例用法:
final Random rnd = new Random();
for (int i = 0; i < 5; i++) {
final String value = String.valueOf(i);
execute(new Callable<String>() {
@Override
public String call() throws Exception {
int sleep = rnd.nextInt(10) * 100;
System.out.println("sleep in " + sleep);
Thread.sleep(sleep);
return value;
}
});
}
虽然执行时间不同,但结果总是按顺序排列:
sleep in 900
result is 0
sleep in 300
result is 1
sleep in 0
result is 2
sleep in 500
result is 3
sleep in 600
result is 4
我也使用future
,但它也不起作用。
private static void execute(Callable<String> request){
Future<String> future = threadPool.submit(request);
try {
String result = future.get();
System.out.println("result is " + result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
请告诉我该怎么做?提前谢谢。
答案 0 :(得分:2)
您没有正确使用CompletionService
。您的主线程正在生成和任务消耗结果。 CompletionService
旨在解除生产和消费;当你有不同的线程播放这些角色时,你会使用它。 execute()
方法毫无意义;它实际上是这样做的,但是有很多混淆和开销:
public void execute(Callable<String> request) {
try {
System.out.println("result is " + request.call());
} catch (Exception ex) {
ex.printStackTrace();
}
}
如果必须在准备好后立即使用结果,则必须完成该任务的一部分。否则,您需要一个应用程序线程等待每个任务完成,因为如果不这样做,任务结果可能就绪,并且必须等待线程可用来使用它。如果每个任务已经有一个线程,为什么要使用线程池?
更明确地说,如果你想保证不等待,你需要做这样的事情:
final class MyTask implements Callable<Void> {
private final String value;
MyTask(String value) { this.value = value; }
@Override
public Void call() throws InterruptedException {
String result = doWork();
handleResult(result);
return null;
}
private String doWork() throws InterruptedException {
int sleep = ThreadLocalRandom.current().nextInt(10) * 100;
System.out.println("sleep in " + sleep);
Thread.sleep(sleep);
return value;
}
private void handleResult(String result) {
System.out.println("result is " + result);
}
}
如果要使用CompletionService
,则需要一些来自服务take()
的单独线程。但是在这种方法中,如果任务的完成速度超过了它们的消耗速度,那么一些结果将会等待。
答案 1 :(得分:0)
R4j,
get()等待callable返回来自call的值:如果你想提交5个请求,你需要提交所有请求,然后调用get