非同期タスクまたは並行タスクを実行する場合、多くの場合、新しいスレッドは直接 new Thread() メソッドによって作成されます。これには多くの欠点があります。より良い解決策は、スレッド プールを合理的に利用することです。スレッド プールを使用すると、システム リソースの消費を削減できます。 、システムの応答速度が向上し、同時スレッド数の管理と制御が容易になります。
スレッドプールのコード例
@Configuration
@EnableAsync
public class ThreadPoolManager {
Logger logger = LoggerFactory.getLogger(ThreadPoolManager.class);
/**
* testAsyncTaskExecutor线程池
* */
@Bean("testAsyncTaskExecutor")
public ThreadPoolTaskExecutor asynRecalculateExcutor(){
logger.info("testAsyncTaskExecutor异步线程池开启");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程数
executor.setCorePoolSize(50);
//最大线程数
executor.setMaxPoolSize(200);
//核心线程数之外的线程存活时间
executor.setKeepAliveSeconds(60*2);
//队列大小
executor.setQueueCapacity(1500);
//线程名称前缀
executor.setThreadNamePrefix("test_Async_Task_Executor_");
//异步重算线程池修饰器。
executor.setTaskDecorator(new ContextCopyingDecorator());
//当任务完成后,长时间无待处理任务时,销毁线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
/**
* 线程池修饰类
* 注意线程池中有的线程是一直存在一直被复用的,
* 所以线程执行完成后需要在TaskDecorator的finally方法中移除传递的上下文对象,否则就存在内存泄漏的问题。
* TaskDecorator是一个执行回调方法的装饰器,主要应用于传递上下文,或者提供任务的监控/统计信息。
*/
public class ContextCopyingDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
try {
RequestAttributes context = RequestContextHolder.currentRequestAttributes();
Map<String,String> previous = MDC.getCopyOfContextMap();
SecurityContext securityContext = SecurityContextHolder.getContext();
return () -> {
try {
RequestContextHolder.setRequestAttributes(context);
MDC.setContextMap(previous);
SecurityContextHolder.setContext(securityContext);
runnable.run();
} finally {
RequestContextHolder.resetRequestAttributes();
MDC.clear();
SecurityContextHolder.clearContext();
}
};
} catch (IllegalStateException e) {
return runnable;
}
}
}
}
使い方?
1. Bean の使用法を注入する
@Resource(name = "testAsyncTaskExecutor")
ThreadPoolTaskExecutor executor;
2. @Async アノテーション非同期メソッド
//在项目中, 偶尔需要使用异步的方式去执行任务.所以,我们可以引入多线程的使用,SpringBoot中支持多线程,使用@EnableAsync注解就可以使用多线程了,@Async放在需要异步执行的方法上,非常简单方便的使用多线程去完成任务.
@Async("testAsyncTaskExecutor")
@Override
public void test() {
//代码
}
execute()メソッドの実行とsubmit()メソッドの実行の違いは何ですか?
1.execute() メソッドは戻り値を必要としないタスクを送信するために使用されるため、タスクがスレッド プールによって正常に実行されたかどうかを判断することはできません。
2. submit() メソッドは、戻り値を必要とするタスクを送信するために使用されます。スレッド プールは、future 型のオブジェクトを返します。この future オブジェクトを通じて、タスクが正常に実行されたかどうかを判断でき、future の get() メソッドを通じて戻り値を取得できます。get() メソッドは、現在のスレッドをブロックします。タスクが完了するまで get (長いタイムアウト、TimeUnit 単位) メソッドを使用すると、現在のスレッドが一定期間ブロックされ、すぐに返されますが、この時点ではタスクが完了しない可能性があります。
ThreadPoolTaskExecutorのソースコードの一部
@Override
public void execute(Runnable task) {
Executor executor = getThreadPoolExecutor();
try {
executor.execute(task);
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}
@Override
public void execute(Runnable task, long startTimeout) {
execute(task);
}
@Override
public Future<?> submit(Runnable task) {
ExecutorService executor = getThreadPoolExecutor();
try {
return executor.submit(task);
}
catch (RejectedExecutionException ex) {
throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
}
}