Резюме использования ListenalbeFuture

Java

Для повышения скорости обработки задач мы часто обрабатываем некоторые шаги, которые можно обрабатывать параллельно асинхронным образом.Если вы хотите получить результаты асинхронных вычислений, до Java 8 мы использовали большеFuture + Callableспособ достижения, ниже приведена демонстрация с использованием Future и Callable, котораяexecutor.submit()То, что на самом деле возвращает метод,FutureTask, а метод get класса Future будет блокироваться до тех пор, пока не будет получен результат.

public class FutureTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Integer> future = executor.submit(new MyCallable(3, 10));
        // get方法会阻塞,直至获取结果
        System.out.println(future.get());
        executor.shutdown();
    }
}

class MyCallable implements Callable<Integer> {
    private int a;
    private int b;

    public MyCallable(int a, int b) {
        this.a = a;
        this.b = b;
    }
    @Override
    public Integer call() throws Exception {
        return a * b;
    }
}

Хотя у Future есть родственные методы для обеспечения возможности асинхронного программирования, получать результаты очень неудобно.Результаты можно получить только путем блокировки или опроса.Метод блокировки явно противоречит первоначальному замыслу нашего асинхронного программирования, а метод опроса также потребляет много ресурсов ЦП, и результаты вычислений не могут быть получены вовремя. Столкнувшись с этой ситуацией, почему бы не использовать метод, аналогичный режиму наблюдателя, и уведомлять задачу мониторинга в режиме реального времени, когда результат установлен? известныйguavaПакет предоставляет расширенные Futures, такие как ListenableFuture и SettableFuture, а также вспомогательные классы Futures. Подобное также доступно в JDK 8.ListenableFutureизCompletableFutureИнтерфейс, который содержит множество API, которые будут представлены один за другим в последующих статьях. Ниже мы в основном представляем использование Guava Future.

Представляем гуаву

Последняя версия Guava доступна по адресуMaven CenterНайти в

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>23.0</version>
</dependency>

Создание ListeningExecutorService

Чтобы поддерживать собственный режим прослушивания, Guava создала новыйExecutorService, называетсяListeningExecutorService, мы можем использоватьMoreExecutorсоздать это

// 创建一个由invoke线程执行的线程池
 ListeningExecutorService executorService = MoreExecutors.newDirectExecutorService();
 // 装饰自定义的线程池返回
 ListeningExecutorService executorService1 = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());

После создания пула потоков мы можем создатьListenableFutureохватывать

ListenableFuture<?> listenableFuture = executorService.submit(new MyCallable(3, 10));

Добавить слушателя (addListener)

Интерфейс прослушивания профиля проходит из будущего интерфейса и добавляет новый метод.addListener, метод заключается в добавлении слушателя к асинхронной задаче

  listenableFuture.addListener(() -> {
        System.out.println("listen success");
        doSomeThing();
    }, executorService);

Добавить обратный вызов (Futures.addCallBack)

addListenerМетод не поддерживает получение возвращаемого значения, если вам нужно получить возвращаемое значение, вы можете использоватьFutures.addCallBackСтатический метод, этот класс является расширением JDK Future.

// FutureCallback接口包含onSuccess()、onFailure()两个方法
Futures.addCallback(listenableFuture, new FutureCallback<Object>() {
    @Override
    public void onSuccess(@Nullable Object result) {
        System.out.println("res: " + result);
    }

    @Override
    public void onFailure(Throwable t) {}
}, executorService);

Объединение нескольких фьючерсов (Futures.allAsList)

Если вам нужно получить значения нескольких фьючерсов одновременно, вы можете использоватьFutures.allAsList, следует отметить, что если какое-либо Future имеет исключение во время выполнения, оно будет выполнено толькоonFailure()метод, если вы хотите, чтобы Future возвращался нормально, вы можете использоватьFutures.successfulAsListметод, который будет использовать результат неудачного или отмененного Future сnullвместо этого не позволит программе войтиonFailure()метод

ListenableFuture<Integer> future1 = executorService.submit(() -> 1 + 2);
ListenableFuture<Integer> future2 = executorService.submit(() -> Integer.parseInt("3q"));
ListenableFuture<List<Object>> futures = Futures.allAsList(future1, future2);
futures = Futures.successfulAsList(future1, future2);

Futures.addCallback(futures, new FutureCallback<List<Object>>() {
    @Override
    public void onSuccess(@Nullable List<Object> result) {
        System.out.println(result);
    }
    @Override
    public void onFailure(Throwable t) {
        t.printStackTrace();
    }
}, executorService);

Преобразование возвращаемого значения (Futures.transform)

Если вам нужно обработать возвращаемое значение, вы можете использоватьFutures.transformметод, который является синхронным методом, и дополнительный асинхронный методFutures.transformAsync

// 原Future
ListenableFuture<String> future3 = executorService.submit(() -> "hello, future");
// 同步转换
ListenableFuture<Integer> future5 = Futures.transform(future3, String::length, executorService);
// 异步转换
ListenableFuture<Integer> future6 = Futures.transformAsync(future3, input -> Futures.immediateFuture(input.length()), executorService);

немедленное будущее и немедленное отмененное будущее

immediateFutureМетод немедленно вернет возвращаемое значение.ListenableFuture,immediateCancelledFutureвернет немедленно отмененныйListenableFuture, поэтому он возвращает FutureisDoneметод всегда ложный

JdkFutureAdapters

Этот метод можетJDK FutureПревратиться вListenableFuture

Future<String> stringFuture = Executors.newCachedThreadPool().submit(() -> "hello,world");
ListenableFuture<String> future7 = JdkFutureAdapters.listenInPoolThread(stringFuture);
System.out.println(future7.get());

SettableFuture

SettableFutureЕго можно рассматривать как асинхронный инструмент для синхронного, который можно получить в течение определенного времени.ListenableFutureрезультат расчета

SettableFuture<Integer> settableFuture = SettableFuture.create();
ListenableFuture<Integer> future11 = executorService.submit(() -> {
    int sum = 5 + 6;
    settableFuture.set(sum);
    return sum;
});
// get设置超时时间 
System.out.println(settableFuture.get(2, TimeUnit.SECONDS));

Оригинальный адрес:Резюме использования ListenalbeFuture