java 番石榴期货等待回调
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17671957/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Guava Futures Wait for Callback
提问by vinoths
I have a list of futures and on completion of each future, I have a callback that should get executed.
我有一个期货列表,在每个期货完成后,我有一个应该执行的回调。
I am using Futures.successfulAsList to check if all the futures have completed. However, this doesn't take into account the completion of callback.
我正在使用 Futures.successfulAsList 来检查所有期货是否已完成。但是,这并没有考虑回调的完成。
Is there a way I can ensure the callback is completed?
有没有办法确保回调完成?
Instead of Callback, I could use Futures.transform to wrap into another Future and check for completion of that. However, with this, I don't get access to runtime exception thrown in the wrapped future.
代替回调,我可以使用 Futures.transform 包装到另一个 Future 并检查它是否完成。但是,有了这个,我无法访问包装的未来中抛出的运行时异常。
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(20));
List<ListenableFuture<Object>> futures = new ArrayList<>();
for (int i = 1; i <= 20; i++) {
final int x = i * 100;
ListenableFuture<Object> future = service.submit(new Callable() {
@Override
public Object call() throws Exception {
Thread.sleep(10000 / x);
return x;
}
});
futures.add(future);
Futures.addCallback(future, new FutureCallback<Object>() {
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
@Override
public void onSuccess(Object x) {
try {Thread.sleep((Integer) x * 10);} catch (Exception e) {}
System.out.println(x);
}
});
}
ListenableFuture<List<Object>> listFuture = Futures
.successfulAsList(futures);
System.out.println("Waiting...");
System.out.println(listFuture.get());
System.out.println("Done");
回答by ColinD
If you just want to block until the callbacks for the N tasks you submit have all completed, you could create a CountDownLatch
with a count
of N. Then just call countDown()
on it when each callback completes (whether it succeeds or fails) and await()
it at the point you want to block.
如果你只是想阻塞直到你提交的 N 个任务的回调都完成了,你可以创建一个CountDownLatch
acount
的 N。然后countDown()
在每个回调完成时调用它(无论它成功还是失败),await()
它在你想阻止。
Alternatively, you could do something like you did in your answer, but rather than using a ListenableFutureTask<Void>
and a no-op Runnable
, just use a SettableFuture<Void>
instead and call set(null)
on it on completion.
或者,您可以像在答案中那样做一些事情,但不要使用 aListenableFutureTask<Void>
和 no-op Runnable
,而是使用 aSettableFuture<Void>
并set(null)
在完成时调用它。
回答by user2543253
How about if you create another future for each callback and make sure that it will be completed inside the callback.
如果您为每个回调创建另一个未来并确保它将在回调内完成,那如何。
// create "callback" future here
futures.add(callbackFuture);
Futures.addCallback(future, new FutureCallback<Object>() {
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
// do something with callbackFuture
}
@Override
public void onSuccess(Object x) {
try {Thread.sleep((Integer) x * 10);} catch (Exception e) {}
System.out.println(x);
// do something with callbackFuture
}
});
回答by vinoths
Thankyou, this works!
谢谢,这有效!
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(20));
List<ListenableFuture<Void>> futures = new ArrayList<>();
for (int i = 1; i <= 20; i ++) {
final int x = i * 100;
ListenableFuture<Object> future = service.submit(new Callable(){
@Override
public Object call() throws Exception {
Thread.sleep(10000 / x);
return x;
}
});
//Blank runnable to evaluate write completion
Runnable callback = new Runnable(){
@Override
public void run() {
//do nothing
}
};
final ListenableFutureTask<Void> callbackFuture = ListenableFutureTask.create(callback, null);
futures.add(callbackFuture);
Futures.addCallback(future, new FutureCallback<Object>() {
@Override
public void onFailure(Throwable t) {
try {
t.printStackTrace();
}
finally {
callbackFuture.run();
}
}
@Override
public void onSuccess(Object x) {
try {
try {Thread.sleep((Integer)x*10);}catch(Exception e){}
System.out.println(x);
}
finally {
callbackFuture.run();
}
}
});
}
ListenableFuture<List<Void>> listFuture = Futures.successfulAsList(futures);
System.out.println("Waiting...");
System.out.println(listFuture.get());
System.out.println("Done");
回答by George_A
Realization without sleep:
不睡觉的实现:
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(20));
List<ListenableFuture<Object>> futures = new ArrayList<>();
for (int i = 1; i <= 20; i++) {
final int x = i * 100;
ListenableFuture<Object> future = service.submit(new Callable() {
@Override
public Object call() throws Exception {
Thread.sleep(10000 / x);
return x;
}
});
Futures.addCallback(future, new FutureCallback<Object>() {
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
@Override
public void onSuccess(Object x) {
try {Thread.sleep((Integer) x * 10);} catch (Exception e) {}
System.out.println(x);
}
});
/* all Callbacks added in one list (ExecutionList) and executed by order. If not defined 3d argument (Executor)
then callbacks executed sequentially at task thread.
*/
final SettableFuture<Object> lastCalledFuture = SettableFuture.create();
Futures.addCallback(future, new FutureCallback<Object>() {
@Override
public void onSuccess(Object result) {
lastCalledFuture.set(result);
}
@Override
public void onFailure(Throwable t) {
lastCalledFuture.setException(t);
}
});
futures.add(lastCalledFuture);
}
ListenableFuture<List<Object>> listFuture = Futures
.successfulAsList(futures);
System.out.println("Waiting...");
System.out.println(listFuture.get());
System.out.println("Done");