目录
前言: JUC介绍:
概念: 从java5开始,JDK多了个java.util.concurrent包,简称:JUC。
目的:提供了多种类,方法,为了让开发人员者对于多线程的操作更加方便。
包含的功能:①Executor: 线程池
(见下图解) ②Atomic: 原子操作类
③Lock: 锁
④Tools: 信号量工具类
⑤并发集合: 提供了线程安全的集合类
今天提供的就是JUC功能之一——线程池
一. 线程池理论
1.什么是线程池?
①内存中的一块空间中存放了一些已经创建好的线程对象;
②当代码需要使用线程时无需创建,直接在线程池中调用即可, 当线程执行结束或者销毁时, 会将线程重新放入线程池中, 而不是让线程处于死亡状态。
2.为什么要使用线程池?
线程的建成和销毁会消耗系统的资源,若是频繁如此操作,会消耗大量系统资源;使用线程池就会避免这些问题。
3.使用线程池的特点?
优点:①降低系统资源的消耗。通过重用线程对象,降低因为新建和销毁产生的系统消耗;
②提高系统响应速度。直接从内存中获取线程对象,比新建线程更快;
③提高线程的可管理性。通过对线程池中线程数量的限制,避免无限创建线程导致的 内存溢出或CPU资源耗尽等问题。
缺点:默认情况下,无论是否需要使用线程对象,线程池中都会有一些线程对象,也就是说 会占用一定内存。
二.线程池
1.Executor介绍:
Executor 线程池顶级接口, 接口中只有一个execute()方法,方法参数为Runnable类型。
底层源码展示:
public interface Executor {
void execute(Runnable command);
}
2. ThreadPoolExecutor类
2.1介绍:ThreadPoolExecutor是JUC中提供的默认线程池类,Executor的子类
2.2构造方法(四种):
2.3最多的构造方法有7个参数:
3.ThreadPoolExecutor构造参数详解
①CorePoolSize: 核心线程数
创建线程池后,默认没有任何线程, 当需要线程执行任务时,才会创建核心线程,知道 核心线程数到达指定数量。
当实际核心线程数小于CorePoolSize, 往线程池添加任务时,不会使用执行完任务的 空闲线程,而是创建新的线程,直到实际线程数量等于CorePoolSize。
当实际线程数大于CorePoolSize时, 新任务会寻找空闲下的线程, 若没有就会存储 到工作队列中。
②maximumPoolSize最大线程数
当所有核心线程都被使用中,并且工作队列已经存满,这时线程池就会创建临时线 程来执行任务,直到临时线程数量等于maximumPoolSize。
当所有核心线程都被使用中,工作队列已经存满,并且临时线程数量等于 maximumPoolSize时,这时线程池就会拒绝处理任务(拒绝策略)并抛出异常。
③workQueue工作队列(FIFO先进先出)
Ⅰ非阻塞队列:
ConcurrentLinkedQueue 并发队列
ConcurrentLinkedQueue底层使用的是单向列表
Ⅱ 阻塞队列(有界队列和无界队列):
含义:阻塞是指在入队和出队的时候会有阻塞(等待)效果。
优点:阻塞式队列最大的好处就是能够防止队列容器溢出, 队列容器不溢出 那么我们的数据就不会丢失。
接口:BlockingQueue实现类:
Ⅰ.ArrayBlockingQueue 阻塞有界队列
特点:底层数组;固定长度;
Ⅱ.LinkedBlockingQueue 阻塞队列
特点:底层单向非循环链表;
有参:有界队列;
无参:长度为1<<30,数量过大相当于无界;
Ⅲ.SynchronousQueue队列:它是一个不存储任何元素的队列,相当于一个中专站的效果
④keepAliveTime: 线程最大存活时间
线程池中存在空闲的线程, 就会处于空闲(alive)状态, 只要超过keepAliveTime, 空闲的线程就会被销毁,直到线程池中的线程数等于corePoolSize
如果设置了allowCoreThreadTimeOut=true(默认false),核心线程也可以被销毁
⑤unit: 存活时间单位
//纳秒 NANOSECONDS(TimeUnit.NANO_SCALE), //微妙 MICROSECONDS(TimeUnit.MICRO_SCALE), //毫秒 MILLISECONDS(TimeUnit.MILLI_SCALE), //秒 SECONDS(TimeUnit.SECOND_SCALE), //分钟 MINUTES(TimeUnit.MINUTE_SCALE), //小时 HOURS(TimeUnit.HOUR_SCALE), //天 DAYS(TimeUnit.DAY_SCALE);
⑥threadFactory: 线程工厂
创建线程对象
⑦handler: 拒绝策略
只有当任务队列已满,且线程数量已经达到maximunPoolSize才会触发拒绝策略。
1.AbortPolicy: 丢弃新任务,抛出异常,提示线程池已满(默认)。
2.DisCardPolicy: 丢弃任务,不抛出异常。
3.DisCardOldSetPolicy: 将消息队列中最先进入队列的任务替换为当前新进来的任 务。
3.CallerRunsPolicy: 由调用该任务的线程处理, 线程池不参与, 只要线程池未关闭,该任务一直在调用者线程中。
三.线程池总结(常见面试题) :
Ⅰ参数总结:
-
corePoolSize: 核心线程数大小
-
maximumPoolSize:最大线程数大小(线程池中一共存在多少个线程)
-
queueCapacity:任务队列最大长度
-
keepAliveSize:线程最大空闲时间
-
allowCoreThreadTimeOut:核心线程超时是否被销毁
-
handler:拒绝策略
-
workQueue:任务队列类型
Ⅱ 创建线程总结:
-
当线程数小于核心线程数时,创建线程, 直到达到指定的核心线程数
-
当线程数大于等于核心线程数,且任务队列未满时,将任务放入任务队列
-
当线程数大于等于核心线程数,且任务队列已满
i. 若线程数小于最大线程数,创建线程, 直到达到最大线程数
ii. 若线程数等于最大线程数,抛出异常,拒绝任务
Ⅲ 线程池直观图形详解