Java线程池ThreadPoolTaskExecutor

在执行一个异步任务或并发任务时,往往是通过直接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(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);
		}
	}

猜你喜欢

转载自blog.csdn.net/Little_Arya/article/details/129270289