赞
踩
在执行一个异步任务或并发任务时,往往是通过直接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() {
//代码
}
1、execute()方法用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功与否;
2、submit()方法用于提交需要返回值的任务。线程池会返回一个future类型的对象,通过这个future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值,get()方法会阻塞当前线程直到任务完成,而使用get(long timeout,TimeUnit unit) 方法则会阻塞当前线程一段时间后立即返回,这时候有可能任务没有执行完。
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); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。