В целом все работает нормально, никакого закрепления не происходит. Но для некоторых запросов может быть операция, которая приводит к закреплению (из-за операции блокировки внутри синхронизированного блока), и я хочу этого избежать. Если я этого не сделаю, я могу оказаться в ситуации, когда все операторы связи будут закреплены и не останется потока платформы для обслуживания запроса.
Операция, которая приводит к закреплению, представляет собой часть сторонней библиотеки. Ожидая исправления, которое позволит мне выполнять код библиотеки без закрепления, я планирую использовать следующий подход:
Отправьте код, который закрепляет носитель виртуального потока, службе исполнителя. (при поддержке потоков платформы) и немедленно вызвать .get() (из виртуального потока) в CompletableFuture, который я получу от исполнителя.
Отредактировано: Вот демонстрационный код (Spring Boot)
Код: Выделить всё
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.time.Instant;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Component
class AppRunner implements ApplicationRunner {
private final Object monitor = new Object();
private final ExecutorService executorService;
public AppRunner() {
this.executorService = Executors.newFixedThreadPool(2);
}
@Override
public void run(ApplicationArguments args) {
String parallelismNum = System.getProperty("jdk.virtualThreadScheduler.parallelism");
System.out.println("jdk.virtualThreadScheduler.parallelism is set to: " + parallelismNum);
try (var virtualExecutor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int taskId = 0; taskId < 100; taskId++) {
final int taskIdentifier = taskId;
System.out.println("Submitting the task to executor: " + taskIdentifier);
virtualExecutor.submit(() -> simpleLongOperation(taskIdentifier));
/**
* If I submit the following instead of pinningOperationOnPlatform,
* My simpleLongOperation would be waiting for a carrier to unpin
*/
// virtualExecutor.submit(() -> pinningOperation(taskIdentifier));
virtualExecutor.submit(() -> pinningOperationOnPlatform(taskIdentifier));
}
}
}
/**
* This runs the pinning operation on a platform thread but awaits on the virtual.
* So no pinning is actually happening.
*/
private void pinningOperationOnPlatform(int id) {
try {
executorService.submit(() -> pinningOperation(id))
.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private void simpleLongOperation(int id) {
System.out.println("\tSIMPLE Start operation " + id + " : " + Instant.now());
sleep(1_000);
System.out.println("\tSIMPLE Complete operation " + id + " : " + Instant.now());
}
private void pinningOperation(int id) {
System.out.println("PINNING Start operation " + id + " : " + Instant.now());
synchronized (monitor) {
sleep(5_000);
}
System.out.println("PINNING Complete pinning operation " + id + " : " + Instant.now());
}
private void sleep(long millis) {
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
На мой взгляд, это не плохо скажется на производительности приложения. Верны ли мои предположения или я что-то упускаю?
Подробнее здесь: https://stackoverflow.com/questions/787 ... orm-thread
Мобильная версия