SpringBootを利用してThreadPoolTaskExecutorで数百万件のデータを一括挿入する
application-dev.properties にスレッドプールの設定情報を追加する
# 非同期スレッド設定
# コアスレッド数を設定する
async.executor.thread.core_pool_size = 30
# 最大スレッド数を設定する
async.executor.thread.max_pool_size = 30
# キューのサイズを設定する
async.executor.thread.queue_capacity = 99988
# スレッドプール内のスレッドの名前の接頭辞を設定する
async.executor.thread.name.prefix = async-importDB-
Spring コンテナにスレッドプールの Bean オブジェクトを注入する
@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig {
@Value("${async.executor.thread.core_pool_size}")
private int corePoolSize;
@Value("${async.executor.thread.max_pool_size}")
private int maxPoolSize;
@Value("${async.executor.thread.queue_capacity}")
private int queueCapacity;
@Value("${async.executor.thread.name.prefix}")
private String namePrefix;
@Bean(name = "asyncServiceExecutor")
public Executor asyncServiceExecutor() {
log.warn("start asyncServiceExecutor");
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
// コアスレッド数を設定する
executor.setCorePoolSize(corePoolSize);
// 最大スレッド数を設定する
executor.setMaxPoolSize(maxPoolSize);
// キューサイズを設定する
executor.setQueueCapacity(queueCapacity);
// スレッドプール内のスレッドの名前の接頭辞を設定する
executor.setThreadNamePrefix(namePrefix);
// rejection-policy:プールが最大サイズに達した場合、新しいタスクをどのように処理するか
// CALLER_RUNS:新しいスレッドでタスクを実行せず、呼び出し元のスレッドで実行する
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
非同期スレッドを作成するビジネスクラス
@Service
@Slf4j
public class AsyncServiceImpl implements AsyncService {
@Override
@Async("asyncServiceExecutor")
public void executeAsync(List<LogOutputResult> logOutputResults, LogOutputResultMapper logOutputResultMapper, CountDownLatch countDownLatch) {
try{
log.warn("start executeAsync");
logOutputResultMapper.addLogOutputResultBatch(logOutputResults);
log.warn("end executeAsync");
}finally {
countDownLatch.countDown();
}
}
}
複数スレッドでバッチ挿入を行う具体的なビジネスメソッドを作成する
@Override
public int testMultiThread() {
List<LogOutputResult> logOutputResults = getTestData();
//100件のデータごとにスレッドを開いてテストする
List<List<LogOutputResult>> lists = ConvertHandler.splitList(logOutputResults, 100);
CountDownLatch countDownLatch = new CountDownLatch(lists.size());
for (List<LogOutputResult> listSub:lists) {
asyncService.executeAsync(listSub, logOutputResultMapper,countDownLatch);
}
try {
//以前のすべてのスレッドが実行を完了するまで、次に進まない
countDownLatch.await();
} catch (Exception e) {
log.error("ブロッキング例外:"+e.getMessage());
}
return logOutputResults.size();
}