Обертывание асинхронного вычисления в синхронное (блокирование) вычисление

подобные вопросы:

У меня есть объект с методом, который я хотел бы выставить клиентам библиотеки (особенно пишущий сценарий клиентов) как что-то как:

interface MyNiceInterface
{
    public Baz doSomethingAndBlock(Foo fooArg, Bar barArg);
    public Future 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 для этого?

47
задан Community 23 May 2017 в 11:54
поделиться

2 ответа

Используя свою собственную будущую реализацию:

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, который очищается после получения обратного вызова. Если пользовательские вызовы поступают, то CountDownLatch используется для блокировки вызывающего потока до завершения вычислений и вызова обратного вызова onBazResult. Функция CountDownLatch гарантирует, что если вызов произойдет до того, как будет вызвана функция get(), то метод get() сразу же вернется с результатом.

46
ответ дан 26 November 2019 в 19:40
поделиться

Ну, есть простое решение:

public Baz doSomethingAndBlock(Foo fooArg, Bar barArg) {
  final AtomicReference<Baz> notifier = new AtomicReference();
  doSomethingAsync(fooArg, barArg, new BazComputationSink() {
    public void onBazResult(Baz result) {
      synchronized (notifier) {
        notifier.set(result);
        notifier.notify();
      }
    }
  });
  synchronized (notifier) {
    while (notifier.get() == null)
      notifier.wait();
  }
  return notifier.get();
}

Конечно, это предполагает, что ваш Baz результат никогда не будет нулевым...

17
ответ дан 26 November 2019 в 19:40
поделиться
Другие вопросы по тегам:

Похожие вопросы: