该版本组合了本人博客中的:自定义线程池——普通版(生产者添加任务到阻塞队列失败时死等)、自定义线程池——超时版(工作线程获取任务超时)
实现逻辑
实现
RefusePolicy:拒绝策略
/**
* 消费型函数式接口
*/
@FunctionalInterface
interface RefusePolicy<T>{
void refuseHandle(BlockingQueue3<T> blockingQueue3,T runnable);
}
ThreadPool3
/**
* 自定义线程池-拒绝策略版:生产者加入阻塞队列失败时执行拒绝策略
*/
@Slf4j(topic = "c.eight-Demo3")
class ThreadPool3{
//线程集合:用来存放工作线程
private HashSet<Wroking> threadsSet;
//集合最大值:用户指定线程池的线程数量
private final int threadsSetSize;
//阻塞队列:工作线程繁忙时存放任务
private BlockingQueue3<Runnable> blockingQueue;
//获取任务超时时间
private long timeout;
//时间单位
private TimeUnit timeUnit;
//拒绝策略
RefusePolicy refusePolicy;
ThreadPool3(int threadsSetSize,int blockingQueueSize,long timeout,TimeUnit timeUnit,RefusePolicy<Runnable> refusePolicy) {
threadsSet=new HashSet<>();
this.threadsSetSize=threadsSetSize;
blockingQueue=new BlockingQueue3(blockingQueueSize);
this.refusePolicy=refusePolicy;
this.timeout=timeout;
this.timeUnit=timeUnit;
}
//1.调用线程池的execute(Runnable r)
public synchronized void execute(Runnable r){
//2.判断线程集合的大小是否>=最大线程数?
if(threadsSet.size()>=threadsSetSize){
//2.2 是,将任务添加到阻塞队列中
blockingQueue.tryPut(r,refusePolicy);
}else {
// 2.1 否,创建Worker对象并添加到线程集合中并启动线程.Worker对象继承Thread
Wroking wroking=new Wroking(r);
threadsSet.add(wroking);
wroking.start();
}
}
//自定义工作线程
class Wroking extends Thread{
//该线程执行的任务内容
Runnable task;
public Wroking(Runnable r) {
task=r;
}
@Override
public void run() {
//在run()中执行Runnable任务,执行完成后从阻塞队列中获取任务继续执行
while(task!=null || (task=blockingQueue.get(timeout,timeUnit))!=null){
task.run();
task=null;
}
//任务全部执行完毕,在线程集合中移除线程。
threadsSet.remove(this);
log.debug("移除线程"+this);
}
}
}
BlockingQueue3
/**
* 自定义阻塞队列
*/
@Slf4j(topic = "c.eight-Demo3")
class BlockingQueue3<T>{
//任务队列
private Deque<T> tasksQueue=new ArrayDeque<>();
//队列最大值
private int blockingQueueSize;
//锁
private ReentrantLock lock=new ReentrantLock();
//消费者条件变量
private Condition Consumer=lock.newCondition();
//生产者条件变量
private Condition Producer=lock.newCondition();
public BlockingQueue3(int blockingQueueSize) {
this.blockingQueueSize=blockingQueueSize;
}
//将任务添加到阻塞队列中
public void tryPut(T r,RefusePolicy refusePolicy) {
lock.lock();
try{
// 3.阻塞队列判断队列大小是否==限制大小
if(tasksQueue.size()==blockingQueueSize){
// 3.2 是,执行拒绝策略
refusePolicy.refuseHandle(this,r);
}else {
// 3.1 否,将任务添加到队列队尾并唤醒消费者条件变量中的阻塞线程
tasksQueue.addLast(r);
Consumer.signal();
}
}finally {
lock.unlock();
}
}
//将任务添加到阻塞队列中-超时等待
public void putOverTime(T r,long timeout,TimeUnit timeUnit){
lock.lock();
//阻塞队列添加任务失败需要等待的时间
long need = timeUnit.toNanos(timeout);
try{
// 3.阻塞队列判断队列大小是否==限制大小
while(tasksQueue.size()==blockingQueueSize){
// 3.2 是,将执行任务的线程阻塞在生产者的条件变量中
if(need>0){
try {
need = Producer.awaitNanos(need);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
return;
}
}
// 3.1 否,将任务添加到队列队尾并唤醒消费者条件变量中的阻塞线程
tasksQueue.addLast(r);
Consumer.signal();
}finally {
lock.unlock();
}
}
//将任务添加到阻塞队列中-死等
public void put(T r) {
lock.lock();
try{
// 3.阻塞队列判断队列大小是否==限制大小
while(tasksQueue.size()==blockingQueueSize){
// 3.2 是,将执行任务的线程阻塞在生产者的条件变量中
try {
Producer.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 3.1 否,将任务添加到队列队尾并唤醒消费者条件变量中的阻塞线程
tasksQueue.addLast(r);
Consumer.signal();
}finally {
lock.unlock();
}
}
//线程任务执行完毕,取任务
public T get(long timeout, TimeUnit timeUnit) {
lock.lock();
//获取不到任务需要等待的时间
long need = timeUnit.toNanos(timeout);
try{
while(tasksQueue.size()==0){
// 2.1.1 队列为空,进入消费者条件变量中进行阻塞
if (need>0){
try {
//等待被唤醒后获得剩余等待时间。
need=Consumer.awaitNanos(need);
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
return null;
}
}
// 2.1.2 队列不为空,获取任务执行并唤醒生产条件变量中的生产线程
T r=tasksQueue.pollFirst();
Producer.signal();
return r;
}finally {
lock.unlock();
}
}
}
测试
代码
public static void main(String[] args) {
ThreadPool3 threadPool = new ThreadPool3(2, 1, 3000, TimeUnit.NANOSECONDS,(queue3,runnable)->{
log.debug("执行拒绝策略");
/* //死等
queue3.put(runnable);
//带超时等待
queue3.putOverTime(1000,TimeUnit.NANOSECONDS);
//让调用者放弃执行任务
log.debug("让调用者放弃执行任务");
//让调用者抛出异常
throw new RuntimeException("阻塞队列添加任务失败!");*/
//让调用者自己执行任务
runnable.run();
});
for (int i = 0; i < 5; i++) {
int j = i;
threadPool.execute(() -> {
log.debug("执行任务" + j);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.debug("任务" + j + "执行完毕");
});
}
}
结果
19:35:53 [Thread-1] c.eight-Demo3 - 执行任务1
19:35:53 [Thread-0] c.eight-Demo3 - 执行任务0
19:35:53 [main] c.eight-Demo3 - 执行拒绝策略
19:35:53 [main] c.eight-Demo3 - 执行任务3
19:35:55 [Thread-0] c.eight-Demo3 - 任务0执行完毕
19:35:55 [Thread-1] c.eight-Demo3 - 任务1执行完毕
19:35:55 [main] c.eight-Demo3 - 任务3执行完毕
19:35:55 [main] c.eight-Demo3 - 执行拒绝策略
19:35:55 [main] c.eight-Demo3 - 执行任务4
19:35:57 [main] c.eight-Demo3 - 任务4执行完毕
19:35:57 [Thread-1] c.eight-Demo3 - 执行任务2
19:35:57 [Thread-0] c.eight-Demo3 - 移除线程Thread[Thread-0,5,main]
19:35:59 [Thread-1] c.eight-Demo3 - 任务2执行完毕
19:35:59 [Thread-1] c.eight-Demo3 - 移除线程Thread[Thread-1,5,main]