类似的问题:
- Pattern for wrapping an Asynchronous JavaScript function to make it synchronous
- Wrapping an asynchronous method synchronously in C#
我有一个对象,我想向库客户端(尤其是脚本客户端)公开一个方法,如下所示:
interface MyNiceInterface
{
public Baz doSomethingAndBlock(Foo fooArg, Bar barArg);
public Future<Baz> doSomething(Foo fooArg, Bar barArg);
// doSomethingAndBlock is the straightforward way;
// doSomething has more control but deals with
// a Future and that might be too much hassle for
// scripting clients
}
但我可用的原始“东西”是一组事件驱动的类:
interface BazComputationSink
{
public void onBazResult(Baz result);
}
class ImplementingThing
{
public void doSomethingAsync(Foo fooArg, Bar barArg, BazComputationSink sink);
}
ImplementingThing 接受输入,做一些神秘的事情,比如在任务队列中排队,然后当结果出现时,sink.onBazResult()
会在一个线程上被调用,该线程可能会也可能不会与调用 ImplementingThing.doSomethingAsync() 的线程相同。
有没有一种方法可以使用我拥有的事件驱动函数以及并发原语来实现 MyNiceInterface,以便脚本客户端可以愉快地等待阻塞线程?
编辑:我可以使用 FutureTask为此?
最佳答案
使用您自己的 Future 实现:
public class BazComputationFuture implements Future<Baz>, BazComputationSink {
private volatile Baz result = null;
private volatile boolean cancelled = false;
private final CountDownLatch countDownLatch;
public BazComputationFuture() {
countDownLatch = new CountDownLatch(1);
}
@Override
public boolean cancel(final boolean mayInterruptIfRunning) {
if (isDone()) {
return false;
} else {
countDownLatch.countDown();
cancelled = true;
return !isDone();
}
}
@Override
public Baz get() throws InterruptedException, ExecutionException {
countDownLatch.await();
return result;
}
@Override
public Baz get(final long timeout, final TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
countDownLatch.await(timeout, unit);
return result;
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public boolean isDone() {
return countDownLatch.getCount() == 0;
}
public void onBazResult(final Baz result) {
this.result = result;
countDownLatch.countDown();
}
}
public Future<Baz> doSomething(Foo fooArg, Bar barArg) {
BazComputationFuture future = new BazComputationFuture();
doSomethingAsync(fooArg, barArg, future);
return future;
}
public Baz doSomethingAndBlock(Foo fooArg, Bar barArg) {
return doSomething(fooArg, barArg).get();
}
该解决方案在内部创建一个 CountDownLatch,一旦接收到回调,它就会被清除。如果用户调用 get,CountDownLatch 用于阻塞调用线程,直到计算完成并调用 onBazResult 回调。 CountDownLatch 将确保如果在调用 get() 之前发生回调,则 get() 方法将立即返回结果。
关于java - 将异步计算包装成同步(阻塞)计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2180419/