一、基本介绍
线程池:
已经包含了一些线程, 以便直接使用.
优点:避免了频繁创建 / 销毁线程的开销
线程池本身就是生产者 - 消费者模型。
生产者 - 消费者模型介绍
核心操作:
execute: 把一个任务加到线程池中
shutdown: 销毁线程池中的所有线程
线程池的组成:(需要管理两个部分: 将要执行的任务, 正在执行任务的线程)
1. 一个类, 描述具体线程要做的工程(借助 Runnable 表示)
2. 需要一个数据结构来组织若干个任务(BlockingQueue)
3. 先有一个类, 表示工作线程
4. 还需要一个数据结构, 组织若干个线程(List)
二、线程池的实现
static class Worker extends Thread {
// 描述当前工作线程
// 每个 Worker 线程都需要从任务队列中取任务
// 需要能够获取到任务队列的实例
private int id = 0;
private BlockingQueue<Runnable> queue = null;
public Worker(BlockingQueue<Runnable> queue, int id) {
this.queue = queue;
this.id = id;
}
@Override
public void run() {
// try 包含 while:
// 目的是只要线程收到异常, 就会立刻结束 run 方法
// 为 shutdown 方法做准备
try {
while (!Thread.currentThread().isInterrupted()) {
// 数据结构建成
Runnable commend = queue.take();
// 如果队列为空, take 就会阻塞
// 阻塞到 execute 插入元素
System.out.println("Thread " + id + " running");
commend.run();
}
}catch (InterruptedException e) {
// 线程被结束
System.out.println("线程被终止");
}
}
}
static class ThredPool {
// 本质就是生产者 消费者模型
// 调用 execute 的是生产者, 生产了任务
// worker 线程是消费者, 消费了队列中的任务
// 阻塞队列用于组织若干个任务
private BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
// List 用于组织若干个工作线程
private List<Worker> workers = new ArrayList<>();
// 线程池内部线程个数(根据实际情况确定)
private static final int maxWorkerCount = 10;
// 实现 execute 方法和 shutdown 方法
public void execute(Runnable command) throws InterruptedException {
// 加人线程池(加入队列)
// 也是使用延时加载的方式来创建线程(需要判断池中线程数目是否小于阈值)
// 若没达到, 则不需新建线程, 否则需要新建一个线程
if (workers.size() < maxWorkerCount) {
Worker worker = new Worker(queue, workers.size());
worker.start();
workers.add(worker); // 加入 ArrayList 中
}
queue.put(command); // 加入阻塞队列中
}
public void shutDown() throws InterruptedException {
// 终止所有线程
for (Worker worker : workers) {
worker.interrupt();
// interrupt(): 中断这个线程
// 这里的作用只是触发线程的 catch 异常, 让 run 方法结束.
// 线程结束, 则对应的 join 方法也返回了.
// 从收到异常到线程结束, 中间还需要执行 catch 中代码, 因此不是瞬时完成.
// interrupted(): 测试当前线程是否中断。
}
// 还需要等待每个线程执行结束
for (Worker worker : workers) {
worker.join();
// join(): 等待这个线程死亡。
}
}
}
static class Command implements Runnable {
private int num;
public Command(int num) {
this.num = num;
}
@Override
public void run() {
System.out.println("正在执行任务: " + num);
}
}
public static void main(String[] args) throws InterruptedException {
ThredPool pool = new ThredPool();
for (int i = 0; i < 1000; i++) {
// i 不是 final 类修饰, 所以不能再匿名内部类或 lamba 中直接调用, 需要重新写一个类(Command) 传入 i.
pool.execute(new Command(i));
}
Thread.sleep(2000); // 休眠 2 秒
pool.shutDown();
System.out.println("线程池已被销毁");
}