为什么要使用ThreadPoolTaskExecutor线程处理类

本文详细解析了ThreadPoolTaskExecutor在Spring框架中的作用,以及它是如何基于JUC包中的ThreadPoolExecutor来管理和使用线程池的。文章介绍了不同类型的线程池创建方式,并解释了ThreadPoolTaskExecutor在实际开发中的配置和使用流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

要说ThreadPoolTaskExecutor这个类,先要从java本身的JUC包讲起,我们首先要知道这一点,java中所有对线程池的管理都要遵循一个接口即ExecutorService,这个接口为我们使用线程池定义了一些规则。

在JUC(java.util.concurrent)包中为我们提供了Executors的静态方法创建几种不同的线程池来使用:

	/**
	创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
	*/
	public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }
    /**
	创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
	*/
    public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
    /**
	创建一个定长线程池,支持定时及周期性任务执行。
	*/
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    @see java.util.concurrent.ScheduledThreadPoolExecutor
    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
    @see java.util.concurrent.ThreadPoolExecutor
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }
	/**
	创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
	*/
    public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

从源码上可以看出,这些创建线程池的方式最终都是调用了ThreadPoolExecutor类的构造方法返回了一个ExecutorService实例。中间涉及的几个对象的继承关系如下:
Executor接口继承关系
这里的ThreadPoolExecutor是一个比较重要的线程池实现类

public class ThreadPoolExecutor extends AbstractExecutorService {
	...
	// runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;
	...
	private volatile int corePoolSize;
	private volatile int maximumPoolSize;
	private volatile long keepAliveTime;
	private static final RejectedExecutionHandler defaultHandler =new AbortPolicy();
	private final BlockingQueue<Runnable> workQueue;
	...
		
}

ThreadPoolExecutor类中定义了我们所熟悉的线程池的生命周期,还有几个核心的参数;
回到正题,ThreadPoolExecutor跟我们所要讲的ThreadPoolTaskExecutor有何关系呢?
上面说到,ThreadPoolExecutor是JUC包中提供给我们管理和使用线程池的实现类,且常常使用Executor工具类的几种静态方法进行实例化使用,但是请注意我们在使用的时候并不是想用线程池就使用诸如Executors.newCachedThreadPool()来创建一个的,这样已经违背线程池出现的原因,即管理宝贵的线程资源。

当当当当(平平平上)~ 轮到Spring出马了,Spring框架中为我们封装了一个类,就是今天的主角ThreadPoolTaskExecutor,实际在使用线程池时我们就使用这个类实现,看源码:

public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport implements AsyncListenableTaskExecutor, SchedulingTaskExecutor {
    private final Object poolSizeMonitor = new Object();
    private int corePoolSize = 1;
    private int maxPoolSize = 2147483647;
    private int keepAliveSeconds = 60;
    private int queueCapacity = 2147483647;
    private boolean allowCoreThreadTimeOut = false;
    @Nullable
    private TaskDecorator taskDecorator;
    @Nullable
    private ThreadPoolExecutor threadPoolExecutor;
    
}

可以看到ThreadPoolTaskExecutor类中维护了一个ThreadPoolExecutor成员变量,此中的端倪就在这里的ThreadPoolExecutor变量。那ThreadPoolTaskExecutor实际开发中是怎么使用的呢?

  1. 步骤一、配置Bean (可以使用配置类或者xml的方式,下面示例的springboot中使用配置类进行配置)
@Configuration
public class ThreadPoolTaskExecutorConfig {
    @Bean("threadPoolTaskExecutor")
    ThreadPoolTaskExecutor getThreadPoolTaskExecutor(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(3);
        threadPoolTaskExecutor.setMaxPoolSize(10);
        threadPoolTaskExecutor.setQueueCapacity(200);
        threadPoolTaskExecutor.setThreadNamePrefix("task-concurrent-work");
        threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 这一步是不需要的,下面会讲解到
        // threadPoolTaskExecutor.initialize();
        return threadPoolTaskExecutor;
    }
}
  1. 步骤二、使用时直接使用@AutoWired注解注入使用
 	@Autowired 
 	ThreadPoolTaskExecutor threadPoolTaskExecutor;

	...
	threadPoolTaskExecutor.execute(() -> System.out.println("执行了线程工作"));
	...

这里添加一个链接参考,讲的比较详细

上面讲到使用配置Bean的方式将ThreadPoolTaskExecutor交给spring进行实例化,在实例化中不需要进行 threadPoolTaskExecutor.initialize(); 这一步操作,为什么呢?
通过看源码我们看到ThreadPoolTaskExecutor类(实际上是其父类)实现了InitializingBean接口,则在spring容器初始化时通过父类实现的afterPropertiesSet()方法最终触发ThreadPoolTaskExecutor中的initializeExecutor方法从而this.threadPoolExecutor = executor;将成员变量中的ThreadPoolExecutor实例化。

protected ExecutorService initializeExecutor(ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
        BlockingQueue<Runnable> queue = this.createQueue(this.queueCapacity);
        ThreadPoolExecutor executor;
        if (this.taskDecorator != null) {
            executor = new ThreadPoolExecutor(this.corePoolSize, this.maxPoolSize, (long)this.keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler) {
                public void execute(Runnable command) {
                    Runnable decorated = ThreadPoolTaskExecutor.this.taskDecorator.decorate(command);
                    if (decorated != command) {
                        ThreadPoolTaskExecutor.this.decoratedTaskMap.put(decorated, command);
                    }

                    super.execute(decorated);
                }
            };
        } else {
            executor = new ThreadPoolExecutor(this.corePoolSize, this.maxPoolSize, (long)this.keepAliveSeconds, TimeUnit.SECONDS, queue, threadFactory, rejectedExecutionHandler);
        }

        if (this.allowCoreThreadTimeOut) {
            executor.allowCoreThreadTimeOut(true);
        }

        this.threadPoolExecutor = executor;
        return executor;
}

另外可以看出,实际上在ThreadPoolTaskExecutor中最终还是使用了ThreadPoolExecutor的构造方法来实现一个线程池的。

综上总结一下, 使用ThreadPoolTaskExecutor线程池时,我们需要将他交给spring进行管理(默认创建一个单例),而在使用时直接注入到组件中使用即可,这样就保证不会滥用线程池了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值