前言
大家好,我是jack xu,本篇是并发编程的第二篇,今天跟大家聊一聊线程池的那点事。本篇文章有点长,小伙们静下心、耐下心来把他看完。。
为什么要使用线程池
1)降低创建线程和销毁线程的性能开销
2)提高响应速度,当有新任务需要执行是不需要等待线程创建就可以立马执行
3)合理的设置线程池大小可以避免因为线程数超过硬件资源瓶颈带来的问题
![656b2ceec3e799063ef97efc616bb4e2.png](https://i-blog.csdnimg.cn/blog_migrate/04ae66493a513f5bc1e68e050b6c5f59.jpeg)
我们来看阿里巴巴的代码规范,在项目中创建线程必须要使用线程池创建,原因就是我说的以上三点
线程池的使用
首先我们来看下UML类图
![71ffd9be7330e48e87dbc0b9ce6203e9.png](https://i-blog.csdnimg.cn/blog_migrate/9e2af803c3630656b3daf724f147cc4c.jpeg)
- Executor:可以看到最顶层是 Executor 的接口。这个接口很简单,只有一个 execute 方法。此接口的目的是为了把任务提交和任务执行解耦。
- ExecutorService:这还是一个接口,继承自 Executor,它扩展了 Executor 接口,定义了更多线程池相关的操作。
- AbstractExecutorService:提供了 ExecutorService 的部分默认实现。
- ThreadPoolExecutor:实际上我们使用的线程池的实现是 ThreadPoolExecutor。它实现了线程池工作的完整机制。也是我们接下来分析的重点对象。
- ForkJoinPool:和ThreadPoolExecutor都继承自AbstractExecutorService,适合用于分而治之,递归计算的算法
- ScheduledExecutorService:这个接口扩展了ExecutorService,定义个延迟执行和周期性执行任务的方法。
- ScheduledThreadPoolExecutor:此接口则是在继承 ThreadPoolExecutor 的基础上实现 ScheduledExecutorService 接口,提供定时和周期执行任务的特性。
搞清楚上面的结构很重要,Executors是一个工具类,然后看创建线程的两种方式,第一种是通过Executors提供的工厂方法来实现,有下面四种方式
Executor executor1 = Executors.newFixedThreadPool(10); Executor executor2 = Executors.newSingleThreadExecutor(); Executor executor3 = Executors.newCachedThreadPool(); Executor executor4 = Executors.newScheduledThreadPool(10);复制代码
第二种是通过构造方法来实现
ExecutorService executor5 = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());复制代码
其实查看第一种方式创建的源码就会发现:
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue()); }复制代码
根本上还是通过调用ThreadPoolExecutor的构造方法,创建时传入不同参数,所以本质上还是只有一种创建线程池的方式,就是用构造方法,这里我不想讲用Executors的工厂方法具体帮我们创建了怎样的线程池,让我们再来看一条阿里巴巴规范。
![a9e900fb3f04173c9799e1453bc7772a.png](https://i-blog.csdnimg.cn/blog_migrate/4465bfd1dd54a0c5f059cffd229c42dc.jpeg)
看到这里大家都明白了吧,正是因为封装性太强了,反而小伙们会不知道怎么用,乱用,滥用,有可能会导致OOM,除非你对创建的这四个线程池了如指掌,所以我介绍了也是白介绍,因为就不在用,接下来我们重点看下ThreadPoolExecutor构造方法里各个参数的含义,构造方法有很多个,我选了一个最完整的。
public ThreadPoolExecutor(int corePoolSize, //核心线程数量 int maximumPoolSize, //最大