本文基于【手写阻塞队列】来实现一个生产者消费者模型的经典实例——线程池!
注意:本文的目的是实现一个简易版的线程池,如需了解Java线程池的详细知识,可以参考这篇文章:https://blog.csdn.net/zhang_qing_yun/article/details/119010029
实现:
/**
* @description: 手写线程池(实质为一个基于阻塞队列的生产者-消费者模型)
* @author: 張青云
* @create: 2021-12-31 23:33
**/
public class MyThreadPool {
// 默认线程池中的线程的数量
private static final int WORK_NUM = 32;
// 默认阻塞队列的大小
private static final int QUEUE_SIZE = 1024;
// 线程数
private final int threadCount;
// 阻塞队列的大小
private final int queueSize;
// 阻塞队列
private MyBlockQueue<Runnable> blockQueue;
// 线程集合
private Set<WorkThread> threads;
public MyThreadPool() {
this(WORK_NUM, QUEUE_SIZE);
}
public MyThreadPool(int threadCount, int queueSize) {
this.threadCount = threadCount;
this.queueSize = queueSize;
blockQueue = new MyLinkedBlockQueue<>(this.queueSize);
threads = new HashSet<>(this.threadCount);
// 初始化线程
for(int i = 0; i < threadCount; i++) {
WorkThread thread = new WorkThread("Thread" + i);
threads.add(thread);
thread.start();
}
}
/**
* 向线程池提交任务
*/
public void execute(Runnable task) {
try {
blockQueue.put(task);
} catch (InterruptedException e) {
System.out.println("提交任务时被中断,提交任务失败!");
}
}
/**
* 关闭线程池
*/
public void shutdown() {
for(WorkThread workThread: threads) {
workThread.close();
workThread = null; // help GC
}
threads.clear();
}
/**
* 工作线程
*/
class WorkThread extends Thread{
public WorkThread(String name) {
super();
setName(name);
}
@Override
public void run() {
// 不断地从阻塞队列中获取任务然后执行
while (!isInterrupted()) {
try {
Runnable take = blockQueue.take();
if(take != null) {
take.run();
}
take = null; // help GC
} catch (InterruptedException e) {
close();
System.out.println("获取任务时被中断!");
}
}
}
public void close() {
this.interrupt();
}
}
}
测试:
public class ThreadPoolMain {
public static void main(String[] args) throws InterruptedException {
MyThreadPool threadPool = new MyThreadPool(3, 5);
// 向线程池中提交100个任务
for(int i = 0; i < 10; i++) {
threadPool.execute(() -> {
System.out.println(Thread.currentThread().getName() + ":Hello World!");
});
}
Thread.sleep(2000);
threadPool.shutdown();
}
}
结果: