一.线程池的概念
线程池是一种管理和复用线程的设计模式,主要用于提高多线程编程中的效率。它通过维护一组线程来执行多个任务,从而避免频繁地创建和销毁线程所带来的性能开销。
线程池里取线程比从系统中申请线程更高效的原因,也是因为线程池是纯用户态,比经过内核态更可控。(内核态和用户态属于操作系统中的概念。操作系统 = 操作系统内核 + 操作系统配套的应用程序。(操作系统配套的应用程序指的是我们电脑上下的软件,比如浏览器。而操作系统的内核指的是操作系统的核心部分,用来负责完成一个操作系统的核心操作。管理向下的硬件资源,调用驱动程序硬件设备等和向上的给应用程序提供稳定的环境和系统API))很多应用程序由内核统一负责管理和服务,内核里的工作就可能很繁忙,以至于提交给内核的任务是不可控的。就没办法第一时间执行我们需要的操作。
二.线程池的参数
这个为java标准库中最复杂的线程池参数,其中还有另外三个,但是搞懂这个其他三个也就懂了。
1.核心线程数和最大线程数
说明此线程是可以扩容的。核心线程数指的是初始状态下有一定会存在多少个线程的数量,而最大线程数是等于核心线程数+非核心线程数的最大值。非核心线程数是通过系统繁忙的需要来创建的。类似于一个公司的正式工和临时工,正式工是不能随便辞退的,但是临时工是在某个时刻公司繁忙的时候才会需要的,公司不繁忙的时候就不会需要,当不需要的时候直接辞退就行了。
2.非核心线程的存活时间和存活时间的单位
设置非核心线程的存活时间是为了当不需要额外的线程时减少系统的开销。
其中空闲时间的单位有以下几种:
3.工作队列
线程池工作过程是典型的“生产者消费者模型”,程序员通过使用submit的操作将需要执行的任务设定到线程池里,线程池内部的工作线程就会负责这些任务。此处就会有一个阻塞队列。这个队列我们可以自行定义容量,自行定义队的类型。
4.线程工厂
这里先解释一下工厂的概念:这里的工厂也是一种设计模式叫工厂设计模式,这个模式是在创建类的实例的时候使用的设计模式。(因为构造方法里面有一个“坑”,用工厂设计模式来填“坑”)
在坐标系中一个点的坐标我们可以通过X和Y来表示,也可以通过极坐标的方式来表示一个点在坐标系中的位置。
这种在Java中没办法构成方法的重载的,所以就需要通过工厂的方式来进行填构造方法的“坑”。工厂设计模式通过“普通方法”(通常静态方法)完成对象构造和初始化。
这是最简单的工厂设计模式。通过static创建对象的方法被称为工厂方法。有时候,工厂方法会放在其他的单独类里面,此时这个类,称为工厂类。
线程池中的是Thread类的工厂类,通过这个类完成Thread的对象创建和初始化操作。并且对线程池中的线程进行批量的设置属性。(此处一般进行调整,就是用标准库提供的ThreadFactory的默认值即可)
ThreadFactory默认值。
需要对线程池中的线程进行批量设置属性通过重写这里的newThread方法即可。
5.拒绝策略(非常重要)
当线程池中的任务队列满了,还需要继续添加队列时,如何进行下一步。这里Java标准库中给了4种不同的拒绝策略。
(i)添加任务时,抛出异常
(ii)线程池拒绝执行,由调用submit的线程负责执行
(iii)把任务队列中最老的任务剔除,执行新添加的任务。
(iv)把任务队列中最新的任务剔除。
三.Executors创建线程池
由于ThreadPoolExecutors功能强大,使用不方便,标准库对这个类进一步的封装了一下。Executors 提供了一些工厂方法,可以更方便的构造出线程池。
其中我们重点了解前两个。第一个设置了非常大的线程数,就可以对线程池进行不停的扩容。第二个把核心线程数和最大线程数设置为相同数目,不会自动扩容。第三个是单个线程池,第四个是带有定时器的线程池。