我們常用ThreadPoolExecutor提供的線程池服務,springboot框架提供了@Async註解,幫助我們更方便的將業務邏輯提交到線程池中異步執行,今天我們就來實戰體驗這個線程池服務;
1 進行線程池配置
@EnableAsync
@Configuration
public class TaskPoolConfig {
@Bean("taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心線程池大小
executor.setCorePoolSize(10);
//最大線程數
executor.setMaxPoolSize(20);
//隊列容量
executor.setQueueCapacity(200);
//活躍時間
executor.setKeepAliveSeconds(60);
//線程名字前綴
executor.setThreadNamePrefix("taskExecutor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
上面我們通過使用ThreadPoolTaskExecutor創建了一個線程池,同時設置了以下這些參數:
核心線程數10:線程池創建時候初始化的線程數
最大線程數20:線程池最大的線程數,只有在緩衝隊列滿了之後纔會申請超過核心線程數的線程
緩衝隊列200:用來緩衝執行任務的隊列
允許線程的空閒時間60秒:當超過了核心線程出之外的線程在空閒時間到達之後會被銷燬
線程池名的前綴:設置好了之後可以方便我們定位處理任務所在的線程池
線程池對拒絕任務的處理策略:這裏採用了CallerRunsPolicy策略,當線程池沒有處理能力的時候,該策略會直接在 execute 方法的調用線程中運行被拒絕的任務;如果執行程序已關閉,則會丟棄該任務
2使用線程池
在方法名上用@Async註解中指定線程池名即可,TaskPoolConfig.java中@Bean的value值
@Async("taskExecutor")
public void doTaskOne() throws Exception {
log.info("開始做任務一");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("完成任務一,耗時:" + (end - start) + "毫秒");
}
3 單元測試
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class ThreadTaskTest {
@Autowired
private ThreadTask task;
@Test
public void test() throws Exception {
task.doTaskOne();
task.doTaskTwo();
Thread.currentThread().join();
}
}
執行上面的單元測試,我們可以在控制檯中看到所有輸出的線程名前都是之前我們定義的線程池前綴名開始的,說明我們使用線程池來執行異步任務的試驗成功了!
一般線程執行方法在一個單獨的類中。