线程池就是创建若干个可执行的线程放入一个池(容器)中,有任务需要处理时,会提交到线程池中的任务队列,处理完之后线程并不会被销毁,而是仍然在线程池中等待下一个任务。
因为 Java 中创建一个线程,需要调用操作系统内核的 API,操作系统要为线程分配一系列的资源,成本很高,所以线程是一个重量级的对象,应该避免频繁创建和销毁。
使用线程池就能很好地避免频繁创建和销毁。
先看下一个简单的 Java 线程池的代码
package constxiong.concurrency.a010;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
/**
* 简单的线程池
* @author ConstXiong
*/
public class ThreadPool {
//阻塞队列实现生产者-消费者
BlockingQueue<Runnable> taskQueue;
//工作线程集合
List<Thread> threads = new ArrayList<Thread>();
//线程池的构造方法
ThreadPool(int poolSize, BlockingQueue<Runnable> taskQueue) {
this.taskQueue = taskQueue;
//启动线程池对应 size 的工作线程
for (int i = 0; i < poolSize; i++) {
Thread t = new Thread(() -> {
while (true) {
Runnable task;
try {
task = taskQueue.take();//获取任务队列中的下一个任务
task.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
threads.add(t);
}
}
//提交执行任务
void execute(Runnable task) {
try {
//把任务方法放到任务队列
taskQueue.put(task);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程池的使用测试
package constxiong.concurrency.a010;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
/**
* 测试线程池的使用
* @author ConstXiong
*/
public class TestThreadPool {
public static void main(String[] args) {
// 创建有界阻塞任务队列
BlockingQueue<Runnable> taskQueue = new LinkedBlockingQueue<>(10);
// 创建 3个 工作线程的线程池
ThreadPool tp = new ThreadPool(3, taskQueue);
//提交 10 个任务
for (int i = 1; i <= 10; i++) {
final int j = i;
tp.execute(() -> {
System.out.println("执行任务" + j);
});
}
}
}
打印结果
执行任务1
执行任务2
执行任务3
执行任务6
执行任务5
执行任务4
执行任务8
执行任务7
执行任务10
执行任务9
这个线程池的代码中
线程池的原理就是这么简单,但是 JDK 中的线程池的功能,要远比这个强大的多。
JDK 中提供的最核心的线程池工具类 ThreadPoolExecutor,在 JDK 1.8 中这个类最复杂的构造方法有 7 个参数。
ThreadPoolExecutor(
int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
JDK 的并发工具包里还有一个静态线程池工厂类 Executors,可以方便地创建线程池,但是由于 Executors 创建的线程池内部很多地方用到了无界任务队列,在高并发场景下,无界任务队列会接收过多的任务对象,导致 JVM 抛出OutOfMemoryError,整个 JVM 服务崩溃,影响严重。所以很多公司,尤其互联网大厂已经不建议使用 Executors 去创建线程。
虽然不建议使用,作为对 JDK 的学习,还是简单介绍一下.
具体使用参见 Executors 的使用示例。
ConstXiong 备案号:苏ICP备16009629号-3