手写Java的线程池
简单实现了一个Java的线程池
拒绝策略
/**
* 拒绝策略
*
* @author zhangqi
* @date 2022/7/26 20:04
*/
@FunctionalInterface
public interface RejectPolicy<T> {
/**
* 拒绝策略
*
* @param taskQueue 任务队列
* @param task 任务
*/
void reject(BlockingQueue<T> taskQueue, T task);
}
阻塞队列
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* 自定义的阻塞队列
*
* @param <T> 类型
*/
@Slf4j
@SuppressWarnings("unused")
public class BlockingQueue<T> {
/**
* 任务队列
*/
private final Deque<T> deque = new ArrayDeque<>();
/**
* 锁 用于多线程获取任务队列中的任务 或 放任务
*/
private final ReentrantLock lock = new ReentrantLock();
/**
* 生产者条件变量 队列满了不能在生产了
*/
private final Condition fullWaitSet = lock.newCondition();
/**
* 消费者条件变量 队列空了不能在生产了
*/
private final Condition emptyWaitSet = lock.newCondition();
/**
* 容量
*/
private final int capacity;
/**
* 构造函数
*
* @param capacity 队列大小
*/
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
/**
* 获取任务 阻塞 带超时时间
*
* @param timeout 超时时间
* @param unit 时间单位
* @return 任务
*/
public T poll(long timeout, TimeUnit unit) {
long nanos = unit.toNanos(timeout);
lock.lock();
try {
while (deque.isEmpty()) {
if (nanos <= 0) {
return null;
}
nanos = emptyWaitSet.awaitNanos(nanos);
}
fullWaitSet.signalAll();
return deque.removeFirst();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
} finally {
lock.unlock();
}
}
/**
* 获取任务 阻塞
*
* @return 任务
*/
public T take() {
lock.lock();
try {
while (deque.isEmpty()) {
emptyWaitSet.awaitUninterruptibly();
}
fullWaitSet.signalAll();
return deque.removeFirst();
} finally {
lock.unlock();
}
}
/**
* 添加任务 阻塞 带超时时间
*
* @param element 任务
* @param timeout 超时时间
* @param unit 时间单位
*/
public boolean offer(T element, long timeout, TimeUnit unit) {
lock.lock();
long nanos = unit.toNanos(timeout);
try {
while (deque.size() == capacity) {
log.info("等待 [{}]", element);
if (nanos <= 0) {
return false;
}
nanos = fullWaitSet.awaitNanos(nanos);
}
deque.addLast(element);
log.info("添加任务 [{}]", element.toString());
emptyWaitSet.signalAll();
return true;
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
return false;
} finally {
lock.unlock();
}
}
/**
* 添加任务 阻塞
*
* @param element 任务
*/
public void put(T element) {
lock.lock();
try {
while (deque.size() == capacity) {
log.info("等待 [{}]", element);
fullWaitSet.awaitUninterruptibly();
}
deque.addLast(element);
log.info("添加 [{}]", element);
emptyWaitSet.signalAll();
} finally {
lock.unlock();
}
}
/**
* 获取队列大小
*
* @return 队列大小
*/
public int size() {
lock.lock();
try {
return deque.size();
} finally {
lock.unlock();
}
}
/**
* 尝试添加
*
* @param rejectPolicy 拒绝策略
* @param element 任务
*/
public void tryPut(RejectPolicy<T> rejectPolicy, T element) {
lock.lock();
try {
if (deque.size() >= capacity) {
rejectPolicy.reject(this, element);
} else {
deque.addLast(element);
log.info("添加 [{}]", element);
emptyWaitSet.signalAll();
}
} finally {
lock.unlock();
}
}
}
线程池
import lombok.extern.slf4j.Slf4j;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* 线程池
*
* @author zhangqi
* @date 2022/7/26 20:06
*/
@Slf4j
@SuppressWarnings("unused")
public class ThreadPool {
/**
* 阻塞队列
*/
private final BlockingQueue<Runnable> taskQueue;
/**
* 线程集合
*/
private final Set<Worker> workers = new HashSet<>();
/**
* 核心线程数
*/
private final int coreSize;
/**
* 超时时间
*/
private final long timeout;
/**
* 时间单位
*/
private final TimeUnit unit;
/**
* 拒绝策略
*/
private final RejectPolicy<Runnable> rejectPolicy;
/**
* 构造函数
*
* @param coreSize 核心线程数
* @param timeout 超时时间
* @param unit 时间单位
* @param queueCapacity 阻塞队列大小
* @param rejectPolicy 拒绝策略
*/
public ThreadPool(int coreSize, long timeout, TimeUnit unit, int queueCapacity, RejectPolicy<Runnable> rejectPolicy) {
this.coreSize = coreSize;
this.timeout = timeout;
this.unit = unit;
this.rejectPolicy = rejectPolicy;
this.taskQueue = new BlockingQueue<>(queueCapacity);
}
/**
* 执行线程池方法
*
* @param task 任务
*/
public void execute(Runnable task) {
synchronized (workers) {
// 没有超过核心线程数
if (coreSize > workers.size()) {
Worker worker = new Worker(task);
log.info("执行任务 = " + worker);
workers.add(worker);
worker.start();
return;
}
log.info("加入任务队列 = " + task);
// 超过核心线程数
// 1. 死等
// 2. 等待超时
// 3. 调用者放弃任务
// 4. 调用者抛出异常
// 5. 调用者自己执行任务
taskQueue.tryPut(rejectPolicy, task);
}
}
/**
* 工作线程
*/
private class Worker extends Thread {
/**
* 工作线程的任务
*/
private Runnable task;
/**
* 构造方法
*
* @param task 任务
*/
public Worker(Runnable task) {
this.task = task;
}
/**
* 执行任务
* 1. task != null 执行task
* 2. task 执行完成 判读阻塞队列是否为空 不为空 取出尾部 任务执行
*/
@Override
public void run() {
/// 死等
/// while (Objects.nonNull(task) || Objects.nonNull((task = taskQueue.take()))) {
// 带超时时间
while (Objects.nonNull(task) || Objects.nonNull((task = taskQueue.poll(timeout, unit)))) {
try {
task.run();
} catch (Exception e) {
e.printStackTrace();
} finally {
task = null;
}
}
synchronized (workers) {
log.info(" worker 移除" + workers);
workers.remove(this);
}
}
}
}
测试代码
public static void main(String[] args) {
// 死等
// ThreadPool threadPool = new ThreadPool(2, 1, TimeUnit.SECONDS, 5, BlockingQueue::put);
// 超时时间
// ThreadPool threadPool = new ThreadPool(2, 2, TimeUnit.SECONDS, 5, (queue, take) -> queue.offer(take, 1, TimeUnit.SECONDS));
// 放弃
// ThreadPool threadPool = new ThreadPool(2, 2, TimeUnit.SECONDS, 5, (queue, take) -> System.out.println("放弃"));
// 异常
// ThreadPool threadPool = new ThreadPool(2, 2, TimeUnit.SECONDS, 5, (queue, take) -> {
// throw new RuntimeException();
// });
// 自己执行
ThreadPool threadPool = new ThreadPool(2, 2, TimeUnit.SECONDS, 5, (queue, take) -> {
take.run();
});
for (int i = 0; i < 15; i++) {
int count = i;
threadPool.execute(() -> {
log.info("count = " + count);
Sleep.sleep(2001);
});
}
}
测试结果
2022-07-26 19:57:35.642 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 执行任务 = Thread[Thread-0,5,main]
2022-07-26 19:57:35.645 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 执行任务 = Thread[Thread-1,5,main]
2022-07-26 19:57:35.645 INFO --- [ Thread-0] c.e.demo.hmjuc.day18.TestThreadPool : count = 0
2022-07-26 19:57:35.646 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@4f7d0008
2022-07-26 19:57:35.646 INFO --- [ Thread-1] c.e.demo.hmjuc.day18.TestThreadPool : count = 1
2022-07-26 19:57:35.646 INFO --- [ main] c.e.demo.hmjuc.day18.BlockingQueue : 添加 [com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@4f7d0008]
2022-07-26 19:57:35.648 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@402a079c
2022-07-26 19:57:35.648 INFO --- [ main] c.e.demo.hmjuc.day18.BlockingQueue : 添加 [com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@402a079c]
2022-07-26 19:57:35.648 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@59ec2012
2022-07-26 19:57:35.648 INFO --- [ main] c.e.demo.hmjuc.day18.BlockingQueue : 添加 [com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@59ec2012]
2022-07-26 19:57:35.648 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@4cf777e8
2022-07-26 19:57:35.648 INFO --- [ main] c.e.demo.hmjuc.day18.BlockingQueue : 添加 [com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@4cf777e8]
2022-07-26 19:57:35.648 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@2f686d1f
2022-07-26 19:57:35.648 INFO --- [ main] c.e.demo.hmjuc.day18.BlockingQueue : 添加 [com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@2f686d1f]
2022-07-26 19:57:35.648 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@3fee9989
2022-07-26 19:57:35.648 INFO --- [ main] c.e.demo.hmjuc.day18.TestThreadPool : count = 7
2022-07-26 19:57:37.651 INFO --- [ Thread-0] c.e.demo.hmjuc.day18.TestThreadPool : count = 3
2022-07-26 19:57:37.651 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@73ad2d6
2022-07-26 19:57:37.651 INFO --- [ Thread-1] c.e.demo.hmjuc.day18.TestThreadPool : count = 2
2022-07-26 19:57:37.651 INFO --- [ main] c.e.demo.hmjuc.day18.BlockingQueue : 添加 [com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@73ad2d6]
2022-07-26 19:57:37.652 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@7085bdee
2022-07-26 19:57:37.652 INFO --- [ main] c.e.demo.hmjuc.day18.BlockingQueue : 添加 [com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@7085bdee]
2022-07-26 19:57:37.652 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@1ce92674
2022-07-26 19:57:37.652 INFO --- [ main] c.e.demo.hmjuc.day18.TestThreadPool : count = 10
2022-07-26 19:57:39.653 INFO --- [ Thread-1] c.e.demo.hmjuc.day18.TestThreadPool : count = 4
2022-07-26 19:57:39.653 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@5700d6b1
2022-07-26 19:57:39.653 INFO --- [ Thread-0] c.e.demo.hmjuc.day18.TestThreadPool : count = 5
2022-07-26 19:57:39.654 INFO --- [ main] c.e.demo.hmjuc.day18.BlockingQueue : 添加 [com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@5700d6b1]
2022-07-26 19:57:39.654 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@6fd02e5
2022-07-26 19:57:39.654 INFO --- [ main] c.e.demo.hmjuc.day18.BlockingQueue : 添加 [com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@6fd02e5]
2022-07-26 19:57:39.654 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@5bcab519
2022-07-26 19:57:39.654 INFO --- [ main] c.e.demo.hmjuc.day18.TestThreadPool : count = 13
2022-07-26 19:57:41.657 INFO --- [ Thread-0] c.e.demo.hmjuc.day18.TestThreadPool : count = 8
2022-07-26 19:57:41.657 INFO --- [ main] com.example.demo.hmjuc.day18.ThreadPool : 加入任务队列 = com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@e45f292
2022-07-26 19:57:41.657 INFO --- [ Thread-1] c.e.demo.hmjuc.day18.TestThreadPool : count = 6
2022-07-26 19:57:41.657 INFO --- [ main] c.e.demo.hmjuc.day18.BlockingQueue : 添加 [com.example.demo.hmjuc.day18.TestThreadPool$$Lambda$2/1471868639@e45f292]
2022-07-26 19:57:43.658 INFO --- [ Thread-0] c.e.demo.hmjuc.day18.TestThreadPool : count = 11
2022-07-26 19:57:43.658 INFO --- [ Thread-1] c.e.demo.hmjuc.day18.TestThreadPool : count = 9
2022-07-26 19:57:45.660 INFO --- [ Thread-1] c.e.demo.hmjuc.day18.TestThreadPool : count = 12
2022-07-26 19:57:45.660 INFO --- [ Thread-0] c.e.demo.hmjuc.day18.TestThreadPool : count = 14
2022-07-26 19:57:48.662 INFO --- [ Thread-1] com.example.demo.hmjuc.day18.ThreadPool : worker 移除[Thread[Thread-0,5,main], Thread[Thread-1,5,main]]
2022-07-26 19:57:48.662 INFO --- [ Thread-0] com.example.demo.hmjuc.day18.ThreadPool : worker 移除[Thread[Thread-0,5,main]]
Process finished with exit code 0