将异步计算包装成同步(阻塞)计算 [英] Wrapping an asynchronous computation into a synchronous (blocking) computation

查看:30
本文介绍了将异步计算包装成同步(阻塞)计算的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

类似问题:

我有一个对象,我想向库客户端(尤其是脚本客户端)公开一个方法,例如:

I have an object with a method I would like to expose to library clients (especially scripting clients) as something like:

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
}

但我可用的原始东西"是一组事件驱动的类:

but the primitive "stuff" I have available is a set of event-driven classes:

interface BazComputationSink
{
    public void onBazResult(Baz result);
}

class ImplementingThing
{
    public void doSomethingAsync(Foo fooArg, Bar barArg, BazComputationSink sink);
}

ImplementingThing 接受输入的地方,做一些神秘的事情,比如在任务队列上排队,然后当结果出现时,sink.onBazResult() 在一个可能或可能不的线程上被调用与调用ImplementingThing.doSomethingAsync() 的线程相同.

where ImplementingThing takes inputs, does some arcane stuff like enqueueing things on a task queue, and then later when a result occurs, sink.onBazResult() gets called on a thread that may or may not be the same thread as ImplementingThing.doSomethingAsync() was called.

有没有一种方法可以使用我拥有的事件驱动函数以及并发原语来实现 MyNiceInterface,以便脚本客户端可以愉快地等待阻塞线程?

Is there a way I can use the event-driven functions I have, along with concurrency primitives, to implement MyNiceInterface so scripting clients can happily wait on a blocking thread?

我可以使用 FutureTask 为此?

推荐答案

使用你自己的 Future 实现:

Using your own Future implemenation:

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() 方法将立即返回结果.

The solution creates a CountDownLatch internally which is cleared once the callback is received. If the user calls get, the CountDownLatch is used to block the calling thread until the computation completes and call the onBazResult callback. The CountDownLatch will assure that if the callback occurs before get() is called the get() method will return immediately with a result.

这篇关于将异步计算包装成同步(阻塞)计算的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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