LoginSignup
4
6

More than 5 years have passed since last update.

Springの@Asyncで利用するTaskExecutorを分ける

Posted at

@Asyncでの非同期処理において、ThreadPoolTaskExecutorをすれば同時実行数の制御が可能となります。
しかし、重要な処理と大して重要でない処理を同じThreadPoolで管理してしまうと、重要でない処理が大量に実行待ち状態になったとき、重要な処理を実行しようとしても、なかなか実行できないといった問題が発生します。

そこで、処理によって利用するTaskExecutorを分けて、別のThreadPoolで管理させようと思います。

実装方法

TaskExecutorを2つBean定義する。
どちらもThreadPoolTaskExecutorで、同時実行可能数は1にしています。

@SpringBootApplication
@EnableAsync
public class TaskApplication {

    public static void main(String[] args) {
        SpringApplication.run(TaskApplication.class, args);
    }

    @Bean
    TaskExecutor importantTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(1);
        executor.setMaxPoolSize(1);
        executor.setQueueCapacity(5);
        return executor;
    }

    @Bean
    public TaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(1);
        executor.setMaxPoolSize(1);
        executor.setQueueCapacity(5);
        return executor;
    }
}

非同期処理を行う部分は以下のように実装します。(インターフェースは省略)
@Asyncで利用するTaskExecutorの名前を指定します。
処理の中で、10秒間のスリープを挟むことによって、実行待ち状態が発生するようにしています。

@Service
@Slf4j
public class TaskServiceImpl implements TaskService {

    @Async("importantTaskExecutor")
    @Override
    public void importantTask() {
        try {
            log.info("start important task");
            TimeUnit.SECONDS.sleep(10);
            log.info("end important task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Async("taskExecutor")
    @Override
    public void task() {
        try {
            log.info("start normal task");
            TimeUnit.SECONDS.sleep(10);
            log.info("end normal task");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

以下のコードで動作を確認しました。

@RestController
@RequiredArgsConstructor
public class TaskAsyncController {

    private final TaskService taskService;

    @GetMapping("/")
    public String task() {
        taskService.task();
        taskService.task();
        taskService.task();
        taskService.task();
        taskService.importantTask();

        return "Success!!";
    }
}

実行すると、taskメソッドは1つ実行されますが、残り3つは実行待ち状態となります。
しかし、importantTaskメソッドは実行待ちにはならず、すぐ実行されます。

これで、別のThreadPoolTaskExecutorが利用できていることがわかります。

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6