线程池,就是把线程提前从系统中申请好,放到一个地方,后面需要使用线程的时候,直接从这个地方取,而不是从系统重新申请,线程用完之后也回到刚才的地方。
线程池的优点:降低线程创建和销毁的开销、提高任务执行的效率、控制并发线程的数量、提供线程的管理和监控等。
标准库的线程池
- 使用 Executors.newFixedThreadPool(10) 可以创建出固定包含10个线程的线程池
- 返回值类型为 ExecutorService
- 通过 ExecutorService.submit 可以注册一个任务到线程池中
public static void main(String[] args) {
ExecutorService pool = Executors.newFixedThreadPool(10);
pool.submit(new Runnable() {
@Override
public void run() {
System.out.println("hello");
}
});
}
Executors 创建线程池的几种方式
- newFixedThreadPool:创建固定线程数的线程池
- newCashedThreadPool:创建线程数目动态增长的线程池
- newSingleThreadExecutor:创建只包含单个线程的线程池
- newScheduledThreadPool:设定延迟时间后执行命令,或者定期执行命令。
Executors本质上是ThreadPoolExecutor类的封装
ThreadPoolExecutor 提供了更多的可选参数,可以进一步细化线程池行为的设定
(1)int corePoolSize,int maximumPoolSize
corePoolSize:核心线程数
maximumPoolSize:最大线程数
Java标准库的线程池中,把里面的线程分成两类:
1.核心线程:会始终存在于线程池内部
2.非核心线程:繁忙的时候,被创建出来,空闲时就会把这些线程真正释放掉
最大线程数 = 核心线程数 + 非核心线程数
(2)long keepAliveTime,TimeUnit unit
允许空闲时间 单位
非核心线程会在线程空闲的时候被销毁
(3)BlockingQueue<Runnable> workQueue
工作队列:线程池的工作过程典型的 “生产者消费者模型”
(4)ThreadFactory threadFactory
线程工厂,是一个用于创建和配置线程的对象。它实际上是一个接口,通常用于创建新线程的工厂类,用来代替直接使用Thread类进行线程的创建。
线程工厂的主要目的是将线程的创建和配置逻辑与应用程序的业务逻辑分离开来,提供一种标准化的方式来创建线程。通过使用线程工厂,可以更好地管理线程的创建、配置和销毁。
(5)RejectedExecutionHandler handler
拒绝策略
1.添加任务的时候直接抛出异常
2.线程池拒接了执行,由调用 submit 的线程负责执行
3.把任务队列中,最老的任务踢掉,然后执行新增加的任务
4.把任务队列中,最新的任务踢掉。
实现线程池
class MyThreadPool{
private BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(1000);
//n表示创建几个线程
public MyThreadPool(int n){
for (int i = 0; i < n; i++) {
Thread t = new Thread(()->{
//循环的从队列中取任务
while(true){
try {
Runnable runnable = queue.take();
runnable.run();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
}
}
//添加任务
public void submit (Runnable runnable){
try {
queue.put(runnable);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public class Pool {
public static void main(String[] args) {
MyThreadPool pool = new MyThreadPool(4);
for (int i = 0; i < 1000; i++) {
int id = i;
pool.submit(()->{
System.out.println("执行任务"+ id + "," + Thread.currentThread().getName());
});
}
}
}