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

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

问题描述

类似问题:





我有一个对象,我想要暴露给库客户端(特别是脚本客户端),如:

  interface MyNiceInterface 
{
public Baz doSomethingAndBlock(Foo fooArg,Bar barArg);
public Future< Baz> doSomething(Foo fooArg,Bar barArg);
// doSomethingAndBlock是直接的方法;
// doSomething有更多的控制,但处理
//未来,这可能太麻烦了
//脚本客户端
}

但是我可用的原语stuff是一组事件驱动的类:

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

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

其中ImplementingThing接受输入,做一些神秘的事情, ,然后稍后当一个结果发生时, sink.onBazResult()在一个线程被调用,该线程可能是或不是与ImplementingThing.doSomethingAsync()被调用相同的线程。



有一种方法,我可以使用事件驱动函数和并发原语来实现MyNiceInterface,以便脚本客户端可以高兴地等待阻塞线程? / p>

编辑:我可以使用 FutureTask for this?

解决方案

使用您自己的未来实现:

  public class BazComputationFuture实现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超时,单位);
return result;
}

@Override
public boolean isCancelled(){
return canceled;
}

@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()方法将立即返回一个结果。


similar questions:

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);
}

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.

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?

edit: can I use FutureTask for this?

解决方案

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();
}

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天全站免登陆