Каковы способы передать threadpoolexecutor в CompletableFuture?

В последнее время я работал над Java CompletableFuture и обнаружил, что мы всегда должны использовать настраиваемый пул потоков. С его помощью я нашел два способа передачи пула потоков в существующий код. Как ниже

Это мой ThreadPool в файле конфигурации

@Override
@Bean(name = "commonThreadPool")
public Executor getAsyncExecutor() {
  return new ThreadPoolTaskExecutor();
}

1. Передача существующего пула потоков в качестве аргумента.

 @Autowired
 @Qualifier("commonThreadPool") 
 TaskExecutor existingThreadPool;       
 CompletableFuture.runAsync(() -> executeTask(),existingThreadPool);

2. Использование асинхронного режима, как показано ниже.

@Async("commonThreadPool")
public void executeTask() {
// Execute Some Task
}

есть ли какой-либо третий способ, где я могу написать обработчик CompletableFuture или переопределить его существующее поведение в одном месте, где я могу передать пользовательский пул потоков. И после этого, где бы я ни использовал приведенный ниже код, он должен выбрать мой существующий ThreadPool вместо пула forkJoin.

 CompletableFuture.runAsync(() -> executeTask());

Что не так с @Async?

Didier L 21.05.2019 00:32
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
9
1
7 283
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Я бы настоятельно рекомендовал этого не делать, но если вы действительно хотите, вы можете использовать отражение, чтобы изменить пул потоков, используемый завершаемым будущим.

public static void main(String[] args) throws Exception {
    // Prints ForkJoinPool.commonPool-worker-1
    CompletableFuture<Void> c = CompletableFuture.runAsync(() -> System.out.println(Thread.currentThread().getName()));
    c.get();

    setFinalStatic(CompletableFuture.class.getDeclaredField("asyncPool"), Executors.newFixedThreadPool(10));

    // Prints pool-1-thread-1
    c = CompletableFuture.runAsync(() -> System.out.println(Thread.currentThread().getName()));
    c.get();
}

static void setFinalStatic(Field field, Object newValue) throws Exception {
    field.setAccessible(true);
    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
    field.set(null, newValue);
}

setFinalStatic взято из https://stackoverflow.com/a/3301720/1398418

Спасибо @Oleg, но я ищу любую существующую вещь, реализованную в Spring, или Spring предоставила нам какой-либо вариант для этого?

Mayur 19.05.2019 12:40

Что вы подразумеваете под «вещью, реализованной Spring»? У весны @Async. Когда вы делаете CompletableFuture.runAsync(() -> executeTask());, вы просто вызываете метод класса стандартной библиотеки Java, это не имеет ничего общего со Spring.

Oleg 19.05.2019 12:54

Я имею в виду любую существующую реализованную конфигурацию Spring, в которой мы можем передать существующий ThreadPool один раз во время настройки приложения, и он будет использоваться внутри каждого CompletableFuture вместо CommonForkJoin.

Mayur 19.05.2019 13:03

Тогда просто сделайте то, что я предложил во время запуска приложения.

Oleg 19.05.2019 13:45

Вы также можете достичь своей цели с помощью аоп. Вам понадобится аспектj, Spring aop недостаточно.

Oleg 19.05.2019 14:16
Ответ принят как подходящий

Не существует стандартного способа замены исполнителя по умолчанию для всех экземпляров CompletableFuture. Но начиная с Java 9 вы можете определить исполнителя по умолчанию для подклассов. Например. с участием

public class MyCompletableFuture<T> extends CompletableFuture<T> {
    static final Executor EXEC = r -> {
        System.out.println("executing "+r);
        new Thread(r).start();
    };

    @Override
    public Executor defaultExecutor() {
        return EXEC;
    }

    @Override
    public <U> CompletableFuture<U> newIncompleteFuture() {
        return new MyCompletableFuture<>();
    }

    public static CompletableFuture<Void> runAsync​(Runnable runnable) {
        Objects.requireNonNull(runnable);
        return supplyAsync(() -> {
            runnable.run();
            return null;
        });
    }

    public static <U> CompletableFuture<U> supplyAsync​(Supplier<U> supplier) {
        return new MyCompletableFuture<U>().completeAsync(supplier);
    }
}

вы сделали все необходимые шаги для определения исполнителя по умолчанию для всех связанных этапов MyCompletableFuture. Удержание исполнителя в EXEC служит только в качестве примера, создавая распечатку при использовании, поэтому, когда вы используете этот пример класса, например

MyCompletableFuture.supplyAsync(() -> "test")
    .thenApplyAsync(String::toUpperCase)
    .thenAcceptAsync(System.out::println);

он будет печатать

executing java.util.concurrent.CompletableFuture$AsyncSupply@65ab7765
executing java.util.concurrent.CompletableFuture$UniApply@119d7047
executing java.util.concurrent.CompletableFuture$UniAccept@404b9385
TEST

Другие вопросы по теме