最近在学习java并发编程看到了线程池这一章,实现一个简单的线程池,重点是明白其中的思想。
分析线程池是一种经典的池化思想的使用,目的主要是
1.降低资源的消耗。创建线程和销毁线程是需要消耗时间的,尤其对那种处理时间短的任务,可能处理任务的时间还没有创建和销毁线程的时间多。
2.提高响应速度,当有任务来的时候,不需要新建线程,直接使用线程池里已有的线程即可工作。
3.线程是稀缺资源,使用线程池可以对线程进行统一的管理监控和调优。
1.保存线程肯定需要一个容器,这里就有数组来存储线程,也称为工作线程组。
2.来不及处理的任务也需要一个容器来处理,这里使用阻塞队列来处理。
public class MyThreadPool {
//默认线程池数量
private static int WORK_NUM = 5;
//默认阻塞队列中存放任务的数量
private static int TASK_COUNT = 100;
//默认的阻塞队列
private final BlockingQueue taskQueue;
//线程数
private final int worker_num;
//工作线程组
private final WorkThread[] workThreads;
public MyThreadPool() {
this(WORK_NUM, TASK_COUNT);
}
public MyThreadPool(int workNum, int taskCount) {
if (workNum < 0) workNum = WORK_NUM;
if (taskCount <= 0) taskCount = TASK_COUNT;
worker_num = workNum;
taskQueue = new ArrayBlockingQueue<>(taskCount);
//提前创建好线程,并启动
workThreads = new WorkThread[worker_num];
for (int i = 0; i < worker_num; i++) {
workThreads[i] = new WorkThread();
workThreads[i].start();
}
}
public void execute(Runnable task) {
try {
taskQueue.put(task);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void destroy() {
for (int i = 0; i < worker_num; i++) {
workThreads[i].stopWork();
workThreads[i] = null; // help GC
}
taskQueue.clear();
}
private class WorkThread extends Thread {
@Override
public void run() {
Runnable r = null;
while (!isInterrupted()) {
try {
r = taskQueue.take();
if (r != null) {
System.out.println(getId() + "号任务准备执行");
r.run();
}
r = null;// help GC
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void stopWork() {
interrupt();
}
}
}
流程
1.先定义了一些参数
2.编写一个内部类WorkThread,这个类就是真正运行任务的线程类。该类中从阻塞队列中获取任务并执行。
3.在构造函数中对参数进行赋值,并创建默认数量的线程并启动。
4.完善线程池的两个方法,execute接收任务,destroy关闭线程池。
这是一个最简易的线程池,存在的问题也有很多,比如
1.在构造函数中,就启动了初始化的线程数量,当我线程使用很慢时?我多创建的那不是浪费了嘛。
2.当我的任务数量突然增加,超过了默认的阻塞队列长度,那上面的线程池就会阻塞,导致应用程序就会阻塞。
那就考虑的很周到,具体可以参考ThreadPoolExecutor这个类来参考jdk的线程池是怎么处理的。



