简介:目前常用的线程池有两种,一种是jdk自带的ThreadPoolExecutor来创建线程池,另一种是spring框架中的ThreadPoolTaskExecutor来创建线程池。
JDK自带的线程池
(1)线程池执行过程入下图:
(2)常用的线程池
使用Executors创建线程池:这是jdk自带的创建线程池的方法。通过Exceutors创建线程池,常见的线程池有四种:
Executors.newFixedThreadPool(int nThreads):固定长度的线程池, 创建一个可重用固定个数的线程池,以共享的无界队列方式来运行这些线程。
Executors.newSingleThreadExecutor():单线程的线程池,只有一个工作现场,保证任务按照指定顺序执行。
Executors.newCachedThreadPool():可缓存的线程池, 先查看池中有没有以前建立的线程,如果有,就直接使用。如果没有,就建一个新的线程加入池中,缓存型池子通常用于执行一些生存期很短的异步型任务
Executors.newScheduledThreadPool(int n):创建定长线程池,支持定时及周期性任务执行。
ThreadPoolExecutor类介绍:该类有四个构造方法,但是三个构造方法都是调用直接调用这一个构造方法:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数介绍:
corePoolSize 是核心线程数量。
maximumPoolSize 是线程池容纳线程的最大数量。
keepAliveTime 是空闲线程的存活时间
TimeUnit 是KeepAliveTime的单位
workQueue 是线程池用到的缓冲队列
threadFactory 是创建线程的工厂
handler 是线程池拒绝任务时的策略
(3)线程池的拒绝策略
线程池的拒绝策略:当线程池以及缓冲队列都满了的时候新提交任务的处理策略就是拒绝策略,有四种。
策略1:中止策略ThreadPoolExecutor.AbortPolicy(),抛弃任务,在调用线程直接抛异常。
策略2:调用者执行策略ThreadPoolExecutor.CallerRunsPolicy,在调用线程直接运行这个任务,阻塞调用线程。
策略3:抛弃旧任务策略ThreadPoolExecutor.DiscardOldestPolicy(),抛弃最旧的任务,然后将新任务插入队列。
策略4:抛弃策略ThreadPoolExecutor.DiscardPolicy(),抛弃这个收到的新任务。
(4)线程池的缓冲队列:
同步移交队列SynchronousQueue:队列的容量是0,也就是生产者放入队列之后,消费者马上消费掉这个任务。如果没有消费者,队列会阻塞生产者,反之,亦然。
有界队列:长度有限的队列
无界队列:长度为无限的有界队列,java中通常将无界队列的长度设置为Integer.MAX_VALUE。
(5)线程池的使用:
第一步:定义线程池:
1. public static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
第二步:向线程池提交任务
1. fixedThreadPool.execute(new Runnable() {
2. @Override
3. public void run() {
4. pushListToEop(temp);
5. }
6. });
spring框架的线程池:ThreadPoolTaskExecutor类
spring线程池和JUC线程池的处理流程和拒绝策略基本一致,这里不多做阐述。这里重点讲一下spring线程池的使用。
第一步:定义一个线程池
1. @Configuration
2. @EnableAsync
3. @Slf4j
4. public class ExecutorConfig {
5.
6. /**
7. * 定义导出服务线程池
8. * @return
9. */
10. @Bean("exportServiceExecutor")
11. public Executor exportServiceExecutor() {
12.
13. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
14.
15. // 核心线程数量:当前机器的核心数
16. executor.setCorePoolSize(
17. Runtime.getRuntime().availableProcessors());
18.
19. // 最大线程数
20. executor.setMaxPoolSize(
21. Runtime.getRuntime().availableProcessors() * 2);
22.
23. // 队列大小
24. executor.setQueueCapacity(Integer.MAX_VALUE);
25.
26. // 线程池中的线程名前缀
27. executor.setThreadNamePrefix("export-");
28.
29. // 拒绝策略:直接拒绝
30. executor.setRejectedExecutionHandler(
31. new ThreadPoolExecutor.AbortPolicy());
32.
33. // 执行初始化
34. executor.initialize();
35.
36. return executor;
37. }
38.
39. }
第二步:再需要异步调用的方法上加上@Async注解,当这个方法执行时会利用spring aop产生一个任务交给线程池,从而实现异步执行。
1. /**
2. * 借助@Async注解,使用线程池执行方法
3. * @param query
4. * @param filename
5. */
6. @Async("exportServiceExecutor")
7. @Override
8. public void asyncExport(UserQueryDTO query, String filename) {
9. export(query, filename);
10. }