Аннотация @Async создает потоки, но только один поток принимает всю нагрузку - PullRequest
0 голосов
/ 23 октября 2018

У меня есть требование сохранять огромную полезную нагрузку для базы данных.Поэтому я решил использовать асинхронный вызов для сохранения пакета записей.Я включил асинхронную обработку с помощью аннотации @EnableAsync.Я также использовал @Async для метода на своем сервисном уровне, как показано ниже:

@Async
@Transactional
public CompletableFuture<Boolean> insertRecords(List<Record> records) {

    recordRepository.saveAll(records);
    recordRepository.flush();
    LOGGER.debug(Thread.currentThread().getName()+" -> inserting);
    return CompletableFuture.completedFuture(Boolean.TRUE);
}

Above method is called from another service method
@Transactional
public void performSomeDB(InputStream is){

     //perform another CRUD operation
    processStream(is);
}

private void processStream(InputStream is){

     //Read stream using JsonReader and load into a list
     // record by record. Once the desired batch is met, pass the 
     // list to insertRecords
    List<Record> records = new ArrayList<>();        
    List<CompletableFuture<Boolean>> statuses = new ArrayList<>();
    while(stream has data){
         records.add(record);
         statuses.add(insertRecords(records);
    }

    System.out.println(statuses.size()); // It returns >1 based on the iterations.      

Часть кода, добавленного выше, более символична, чем реальный код.

Когда я просматривал логи, я вижу, что statuses.size () возвращают значение> 1, что означает, что создается больше потоков.Но только один поток используется для сохранения, и он выполняется последовательно для каждой итерации.

http-nio-9090-exec-10 -> insert records
http-nio-9090-exec-10 -> insert records.
......................................

В журналах я вижу, что только один поток работает и сохраняет пакет записей в последовательном порядке.

Почему только один поток принимает нагрузку для сохранения всех записей.

Мой подход неверен?

Ответы [ 3 ]

0 голосов
/ 23 октября 2018

Если вы используете Java-конфигурацию Spring, ваш класс конфигурации должен реализовывать AsyncConfigurer:

@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {
      @Override
        public Executor getAsyncExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(5);
            executor.setMaxPoolSize(10);
            executor.setQueueCapacity(50);
            executor.setThreadNamePrefix("MyPool");
            executor.initialize();
            return executor;
        }
    }

Для получения более подробной информации см. Ниже документ: http://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/scheduling/annotation/EnableAsync.html

0 голосов
/ 23 октября 2018

Что касается аннотации @Async, самовывоз - вызов асинхронного метода из того же класса - не будет работать.Вы должны создать метод в отдельном классе и ссылаться на него, используя объект bean этого класса.

@Component
public class DbInserter {
@Async
@Transactional
public CompletableFuture<Boolean> insertRecords(List<Record> records) {

    recordRepository.saveAll(records);
    recordRepository.flush();
    LOGGER.debug(Thread.currentThread().getName()+" -> inserting);
    return CompletableFuture.completedFuture(Boolean.TRUE);
}
}
0 голосов
/ 23 октября 2018

Это волшебная и общая идея Async.Он распределяет полную нагрузку без создания нескольких потоков.

...