【线程池概念】
最初引入线程,就是因为进程太重了,频繁创建销毁线程,开销较大
但随着业务上对于性能要求越来越高,此时线程的开销变得明显,无法忽略不计了
「线程池」就是上述问题的解决方案
线程池,就是把线程提前从系统中申请好,放到一个地方,后面需要使用线程时,直接从这个地方来取,而不是从系统中重新申请
线程用完后,也是还回到刚才这个地方
★为什么从线程池中取线程,比从系统中申请,来的更高效呢?
【线程池的类】
java标准库中提供了线程池的类ThreadPoolExecutor,可以直接使用
★corePoolSize,maximumPoolSize
核心线程数和最大线程数
此线程池可以支持「线程扩容」:某个线程池初始情况下可能有M个线程,当发现线程不够用时,会自动增加线程个数
【线程性质】
在java标准库的线程池中,把线程分为两类:
1.核心线程(可以理解为:最少有多少个线程)
2.非核心线程(线程扩容的过程中新增的)
核心线程数+非核心线程数的最大值=最大线程数
核心线程会始终存在于线程池内部
非核心线程繁忙时被创造出来,空闲时释放这些线程
★keepAliveTime,unit
时间数值和时间单位(秒,分,小时等)
非核心线程会在线程空闲时被销毁,这代表非核心线程允许空闲的最大时间,超过这个时间会被销毁
★workQueue
工作队列
线程池的工作过程典型的“生产者消费者模型”,使用时通过例如“submit”这样的方法,把要执行的任务设定到线程池中,线程池内部的工作线程负责执行这些任务
此处就有一个阻塞队列
队列可以指定队列容量和队列类型
★threadFactory
线程工厂
工厂,指的是「工厂设计模式」,一种常见的设计模式,在创建类的实例时使用,由于构造方法有“坑”的,通过工厂设计模式来填坑
Thread类的工厂类,通过这个类完成Thread的实例创建和初始化操作
此处的threadFactory就可以针对线程池中的线程进行批量设置属性
须知,此处一般不会进行调整,就使用标准库提供的threadFactory的默认值即可
★handler
拒绝策略
java标准库中给出了四种不同的拒绝策略
【Executors】
ThreadPoolExecutor功能很强大,但使用很麻烦
java标准库对这个类进行了封装,产生了Executors类
这个类提供了一些工厂方法,可以更方便地构造出线程池
★newCachedThreadPool()
参数设置了非常大的线程数,可以对线程池进行不停地扩容
★newFixedThreadPool()
把核心线程数和最大线程数,设置成了一样的值
固定数量,不会自动扩容
需要由ExecutorService这个类型来接收返回值
//这里设置了线程数为4
★submit()
核心方法,指定一个任务到任务队列中
ExecutorService service = Executors.newFixedThreadPool(4);
for(int i = 0;i < 100;i++){
int id = i;
service.submit(() ->{
Thread current = Thread.currentThread();
System.out.println("hello thread" + id + "," + current.getName());
});
}
★shutdown()
把线程池中所有的线程都终止掉
ExecutorService service = Executors.newFixedThreadPool(4);
for(int i = 0;i < 100;i++){
int id = i;
service.submit(() ->{
Thread current = Thread.currentThread();
System.out.println("hello thread" + id + "," + current.getName());
});
}
//最好不要立即终止,因为可能任务还没执行完呢,线程就终止了
Thread.sleep(1000);
//终止掉线程池中所有线程
service.shutdown();
System.out.println("程序退出");