В последнее время я работал над 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());
Я бы настоятельно рекомендовал этого не делать, но если вы действительно хотите, вы можете использовать отражение, чтобы изменить пул потоков, используемый завершаемым будущим.
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 предоставила нам какой-либо вариант для этого?
Что вы подразумеваете под «вещью, реализованной Spring»? У весны @Async
. Когда вы делаете CompletableFuture.runAsync(() -> executeTask());
, вы просто вызываете метод класса стандартной библиотеки Java, это не имеет ничего общего со Spring.
Я имею в виду любую существующую реализованную конфигурацию Spring, в которой мы можем передать существующий ThreadPool один раз во время настройки приложения, и он будет использоваться внутри каждого CompletableFuture вместо CommonForkJoin.
Тогда просто сделайте то, что я предложил во время запуска приложения.
Не существует стандартного способа замены исполнителя по умолчанию для всех экземпляров 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
Что не так с
@Async
?