前几天写了一个固定大小的连接池,今天通过学习又整理一下线程池的实现逻辑,看完这片代码,Java线程池的基本思想你就能完全hold住,离着高级程序员又近一步,欢迎大家参考和交流。
package com.smallfan.connectionpool;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.HashSet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* @PACKAGE_NAME: com.smallfan.connectionpool
* @NAME: TestThreadPool
* @USER: dell
* @DATE: 2020/5/29
* @PROJECT_NAME: aboutthread
*/
@Slf4j
public class TestThreadPool {
public static void main(String[] args) {
ThreadPool threadPool = new ThreadPool(1, 1000,
TimeUnit.MILLISECONDS, 1, ((queue, task) -> {
//死等
// queue.takeQueue();
//设置超时
// Object o = queue.takeQueueForTime(500, TimeUnit.MILLISECONDS);
//舍弃
// log.info("不干预,放弃 {}",task);
//抛出异常
// throw new RuntimeException("抛出异常"+task);
//交给主线程执行
task.run();
}));
for (int i = 0; i < 5; i++) {
int j = i;
threadPool.execute(() ->
{
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("执行第" + j);
}
);
}
}
}
@Slf4j
class ThreadPool {
//任务对列
private BlockingQueue taskQueue;
//线程集合
private HashSet workers = new HashSet();
//线程数
private int threadSize;
//超时时间
private long timeout;
//时间单位
private TimeUnit timeUnit;
//拒绝策略
private RejectPolicy policy;
public ThreadPool(int threadSize, long timeout, TimeUnit timeUnit, int capacity, RejectPolicy policy) {
this.threadSize = threadSize;
this.timeout = timeout;
this.timeUnit = timeUnit;
taskQueue = new BlockingQueue<>(capacity);
this.policy = policy;
}
public void execute(Runnable task) {
synchronized (workers) {//公共资源保证线程安全
//如果任务数小于threadSize时直接执行
//否则加入到线程对列
if (workers.size() < threadSize) {
log.info("新增worker{}", task);
Worker worker = new Worker(task);
workers.add(worker);
worker.start();
} else {
//taskQueue.putQueue(task);
/**
* 考虑问题
* 1对列满了死等
* 2设置超时时间
* 3舍弃
* 4主线程执行
* 5抛出异常
* 使用设计模式的策略模式解决
*/
taskQueue.tryPut(policy, task);
}
}
}
@FunctionalInterface
interface RejectPolicy {
void reject(BlockingQueue queue, T task);
}
class Worker extends Thread {
private Runnable runnable;
public Worker(Runnable runnable) {
this.runnable = runnable;
}
@Override
public void run() {
/**
* 执行任务
* 1.当runnable直接执行
* 2.当对列里面存在任务时执行
*/
// while (runnable != null || (runnable = taskQueue.takeQueue()) != null) {
while (runnable != null || (runnable = taskQueue.takeQueueForTime(timeout, timeUnit)) != null) {
try {
log.info("执行worker{}", runnable);
runnable.run();
} catch (Exception e) {
e.printStackTrace();
} finally {
runnable = null;//执行后置空
}
}
synchronized (workers) {
log.info("移除worker{}", this);
workers.remove(this);
}
}
}
}
//模拟阻塞队列
@Slf4j
class BlockingQueue {
//1.定义队列大小
private int capacity;
//2.定义双向链表,当做容器
private Deque deque = new ArrayDeque();
//3.定义锁
private ReentrantLock lock = new ReentrantLock();
//4.定义空条件变量
private Condition emptyWaitSet = lock.newCondition();
//5.定义满条件变量
private Condition fullWaitSet = lock.newCondition();
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
//定义获取方法
public T takeQueue() {
lock.lock();
try {
while (deque.isEmpty()) {//若还没有
try {
emptyWaitSet.await();//空等待放入时唤醒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//若已经放入
T t = deque.removeFirst();
fullWaitSet.signal();//唤醒满条件
return t;
} finally {
lock.unlock();//释放锁,避免死锁
}
}
//定义超时获取
public T takeQueueForTime(long timeout, TimeUnit unit) {
lock.lock();
long nanos = unit.toNanos(timeout);//统一时间单位
try {
while (deque.isEmpty()) {//若还没有
try {
if (nanos <= 0) {
return null;
}
nanos = emptyWaitSet.awaitNanos(nanos);//防止虚假唤醒 使用等待时间减去消耗时间
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//若已经放入
T t = deque.removeFirst();
fullWaitSet.signal();//唤醒满条件
return t;
} finally {
lock.unlock();//释放锁,避免死锁
}
}
//定义放入方法
public void putQueue(T task) {
lock.lock();
try {
while (deque.size() == capacity) {//已经满了
try {
fullWaitSet.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
deque.addLast(task);
emptyWaitSet.signal();
log.info("加入队列 {}", task);
} finally {
lock.unlock();
}
}
/**
* 任务多时,设置添加任务的超时时间
*
* @param task
* @param timeout
* @param timeUnit
* @return
*/
public boolean putQueueForTimeOut(T task, long timeout, TimeUnit timeUnit) {
lock.lock();
long nanos = timeUnit.toNanos(timeout);
try {
while (deque.size() == capacity) {//已经满了
try {
if (nanos <= 0) {//添加失败
return false;
}
nanos = fullWaitSet.awaitNanos(nanos);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
deque.addLast(task);
emptyWaitSet.signal();
return true;//添加成功
} finally {
lock.unlock();
}
}
//获取容量
public int getCapacity() {
lock.lock();
try {
return deque.size();
} finally {
lock.unlock();
}
}
public void tryPut(ThreadPool.RejectPolicy policy, T task) {
lock.lock();
try {
if (deque.size() == capacity) {//对列已满 调用策略 让调用者决定
policy.reject(this, task);
} else {//空闲
deque.addLast(task);
emptyWaitSet.signal();
}
} finally {
lock.unlock();
}
}
}