Springの非同期処理機構を試す
Springの非同期処理を試してみます。まずは公式チュートリアルを試しました。
https://spring.io/guides/gs/async-method/
非同期機構の概要がつかめて良いです。
@Async
アノテーションを付与したメソッドは非同期処理となり、mainスレッドとは別スレッドで動作することになります。
同時に @EnableAsync
を付与する必要がありますが、 @Configuration
クラスに付与するとSpringアプリケーション全体で非同期処理機構が有効になります。
@Async
を付与した関数の返り値には Future<T>
ないしは void
にする必要があります。
実装例
@Async
で非同期処理をするサービスクラスの実装例です。
MyAsyncTask.java
@Slf4j public class MyAsyncTask { @Async public void doTask(String id) { log.debug("Thread: {}, Id: {}", Thread.currentThread().getName(), id); } @Async public Future<String> doAsyncTaskWithResults(Integer id) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return CompletableFuture .completedFuture(String.format("Thread: %s, Id: %d", Thread.currentThread().getName(), id)); } }
続いてConfigurationクラスです。今回はJava Configクラスを用いてBean定義をします。
TaskExecutor
のクラスはデフォルトでは SimpleAsyncTaskExecutor
になります。これはデフォルトでは @Async
の呼び出しごとにスレッドが生成され、スレッド数の制限がありません。今回はスレッドプールを用いることにするため、ThreadPoolTaskExecutor
をBean定義に追加しておきます。
@EnableAsync
アノテーションを付与してあります。
AsyncConfiguration.java
@Configuration @EnableAsync @ComponentScan public class AsyncConfiguration { @Bean public MyAsyncTask myAsyncTask() { return new MyAsyncTask(); } @Bean public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(3); executor.initialize(); return executor; } }
mainクラスです。DIコンテナから AsyncConfiguration
クラスのBeanを取得して、非同期メソッドを実行します。非同期処理の結果は List<Future<T>>
になります。
@Slf4j public class AsyncTest { public static void main(String[] args) throws InterruptedException { AbstractApplicationContext context = new AnnotationConfigApplicationContext(AsyncConfiguration.class); MyAsyncTask task = context.getBean(MyAsyncTask.class); List<Future<String>> list = new ArrayList<>(); for (int i = 0; i < 10; i++) { list.add(task.doAsyncTaskWithResults(i)); } for (int i = 0; i < 10; i++) { try { log.debug(list.get(i).get()); } catch (ExecutionException e) { e.printStackTrace(); } } context.close(); } }
実行結果
同時最大実行数が setCorePoolSize になっていることが分かります。
22:36:16.314 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@4c75cab9 22:36:16.323 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor' 22:36:16.437 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor' 22:36:16.438 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory' 22:36:16.440 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor' 22:36:16.441 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor' 22:36:16.442 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAsyncAnnotationProcessor' 22:36:16.443 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.scheduling.annotation.ProxyAsyncConfiguration' 22:36:16.488 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'asyncConfiguration' 22:36:16.493 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'myAsyncTask' 22:36:16.517 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'taskExecutor' 22:36:16.520 [main] INFO org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Initializing ExecutorService 22:36:16.522 [main] INFO org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Initializing ExecutorService 'taskExecutor' 22:36:18.553 [main] DEBUG sample.spring.async.sample1.AsyncTest - Thread: taskExecutor-1, Id: 0 22:36:18.553 [main] DEBUG sample.spring.async.sample1.AsyncTest - Thread: taskExecutor-2, Id: 1 22:36:18.553 [main] DEBUG sample.spring.async.sample1.AsyncTest - Thread: taskExecutor-3, Id: 2 22:36:20.554 [main] DEBUG sample.spring.async.sample1.AsyncTest - Thread: taskExecutor-2, Id: 3 22:36:20.554 [main] DEBUG sample.spring.async.sample1.AsyncTest - Thread: taskExecutor-3, Id: 4 22:36:20.554 [main] DEBUG sample.spring.async.sample1.AsyncTest - Thread: taskExecutor-1, Id: 5 22:36:22.555 [main] DEBUG sample.spring.async.sample1.AsyncTest - Thread: taskExecutor-3, Id: 6 22:36:22.555 [main] DEBUG sample.spring.async.sample1.AsyncTest - Thread: taskExecutor-1, Id: 7 22:36:22.555 [main] DEBUG sample.spring.async.sample1.AsyncTest - Thread: taskExecutor-2, Id: 8 22:36:24.556 [main] DEBUG sample.spring.async.sample1.AsyncTest - Thread: taskExecutor-2, Id: 9 22:36:24.556 [main] DEBUG org.springframework.context.annotation.AnnotationConfigApplicationContext - Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@4c75cab9, started on Sun Jun 02 22:36:16 JST 2019 22:36:24.557 [main] INFO org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor - Shutting down ExecutorService 'taskExecutor'
まずはこんなところです。