Java资源分享网 - 专业的Java学习网站 学Java,上Java资源分享网
【并发编程】自定义简单线程池 PDF 下载
发布于:2024-05-09 09:41:35
(假如点击没反应,多刷新两次就OK!)

【并发编程】自定义简单线程池  PDF 下载 图1

 

 

资料内容:

1、概念图
核心部分:
阻塞队列 BlockingQueue :暂存线程池中无法处理的任务
线程池 ThreadPool :自定义的线程池,内部最多包含 coreSize 个工作线程执行任
工作线程 WorkerThread :执行传递过来的任务
拒绝策略 Rejectpolicy :当阻塞队列已满时采用指定的策略拒绝任务
 
2、流程分析
根据上面的概念图,进一步模拟一遍整个线程池执行的流程:
1. 初始化线程池,指定线程池的参数如核心线程数、阻塞队列容量、超时时间、拒绝策略;
2. 并发生产任务压入线程池执行;
1. 工作线程数未达到设定的核心线程数。新建工作线程执行任务,并将工作线程加
入到线程池中的线程集合中;
2. 工作线程数达到了设定的核心线程数。尝试往阻塞队列中暂存任务,当阻塞队列
已满无法添加时,采用指定的拒绝策略对任务进行拒绝。
3. 工作线程执行完当前任务时,循环从阻塞队列中获取任务并执行直到消费完阻塞队列中的
任务;
4. 当无任务时,将工作线程回收销毁。
 
3、设计思路及实现
整体的设计思路应该由广到细,整体到局部。前面的概念图以及流程分析其实就算是一个整体的
设计了,接下来便是局部的设计了。首先先列举一下需要的部分,分别为:
线程池
工作线程
阻塞队列
拒绝策略
结合上面一二点的描述我们可以得出线程池中用到了工作线程和阻塞队列,而当阻塞队列满时需
要根据拒绝策略进行任务拒绝,因此我们采取自下而上的方式逐一设计需要的几大主体。
 
3.1、拒绝策略
其实拒绝策略就是一段逻辑,通过调用者告知使用哪种方式进行任务拒绝。根据 OOP思想 ,这
一段逻辑我们可以封装成不同的方法,通过传入不同的标识选用不同的方法即可。这里使用了
Java1.8 出现的函数式编程进行设计,将这一个逻辑封装成一个函数式接口,调用者可直接使用
Lambda表达式指定需要的拒绝策略,也可将逻辑封装成一个枚举类,直接传入对应的方法即可,这符
合设计模式中的开闭原则,可维护性更高。
 
1 @FunctionalInterface
2 public interface RejectPolicy<T> {
3    /**
4     * @description 拒绝策略中的拒绝方法,可自定义设置适合的拒绝策略
5     * @author xbaozi
6     * @date 2022/11/18 22:34
7     * @param queue 阻塞队列
8     * @param task 需要拒绝的任务
9     **/
10    void reject(BlockingQueue<T> queue, T task);
11 }

 

3.2、阻塞队列
在该阻塞队列中采取了 公平的FIFO形式 ,避免任务一直得不到消费出现饿死情况,因此内部
需要维护一个双向队列。出于内存层面考虑,我们需要维护一个队列最大容量变量,用于判断队列是
否已满,避免 OOM问题 出现。同时由于阻塞队列为多线程下的共享资源,我们需要对其上锁保证在
并发消费下的原子性。最后为了阻塞队列的拓展性,队列中存放的内容采取泛型设计。
双向队列DequeJava内置的双向队列接口,实现类采用ArrayDeque,在大部分情况下
会比LinkList性能要好一点;
最大容量capacity:基本整形变量,用于判断队列是否已满;
锁对象LOCK:采用可重入锁ReentrantLock实现,并分别设置消费者条件变量与生产者
条件变量,对队列为空与队列已满两种情况进行隔离。