java - 将异步计算包装成同步(阻塞)计算

标签 java concurrency asynchronous blocking

类似的问题:

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

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/

相关文章:

java - int 从最小到最大的所有可能值,使用 Java

java - 我应该从多个线程访问(而不是更改)一个对象吗?

.net - 如何从服务调用主 UI 线程

Java 反射(reflect)方法作用域变量

java - 我想使用 ArrayList 在我的控制台中显示来自数据库的所有数据

java - Parse.com - 解析 long 的值而不是名称/标题

java - Java中的并发——等待执行完成

java - ExecutorService 关闭

c# - 任务和 TAP 异步模式 : differences bwteewn factory. StartNew 和 TaskEx.Run

java - EJB @Asynchronous - 事务在执行几分钟后不活动