一、线程池简介
线程池主要是为了控制运行的线程数量,处理过程中将任务放到队列中,然后在线程创建后启动这些任务,如果线程数超过了最大数量,超出数量的线程排队等候,等其它线程执行完毕,再从队列中取出任务来执行。
线程池主要特点是:线程复用、控制最大并发数(削峰操作)、管理线程。
二、如何使用线程池?
Java
中的线程池是通过Executor
框架实现的,该框架中用到了Executor
、Executors
、ExecutorsService
、ThreadPoolExecutor
类。
三个常用的线程池
实现方法 | 描述 |
---|---|
Executors.newFixedThreadPool(int) | 一池n个固定线程 |
Executors.newSingleThreadExecutor() | 一池单线程 |
Executors.newCachedThreadPool() | 可扩容线程 |
(1)Executors.newFixedThreadPool(int)代码实现
package com.lindaxia.juc.demo;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 线程池案例
* @author lindaxia
* @date 2019/11/1 18:20
*/
public class MyThreadPoolDemo {
public static void main(String[] args) {
System.out.println();
//创建一池n线程数--一个银行网点3个窗口
ExecutorService threadPool = Executors.newFixedThreadPool(3);
try {
for (int i = 1; i <=6; i++) {
threadPool.execute(
()->{
System.out.println(Thread.currentThread().getName()+"\t号服务员提供服务");
}
);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();//关闭线程池
}
}
}
测试结果
(2)Executors.newSingleThreadExecutor()代码实现
// ExecutorService threadPool = Executors.newFixedThreadPool(3);
//一池单线程也能完成多任务
ExecutorService threadPool = Executors.newSingleThreadExecutor();
测试结果
(3)Executors.newCachedThreadPool()代码实现
//一池多线程(一个银行网点3个窗口)
// ExecutorService threadPool = Executors.newFixedThreadPool(3);
//一池单线程(一个银行网点1个窗口)
//ExecutorService threadPool = Executors.newSingleThreadExecutor();
//池扩展线程(一个银行网点可扩展窗口)
ExecutorService threadPool = Executors.newCachedThreadPool();
(1、2、3)方法底层实现源码
三、线程池底层工作原理(非常重要!!!)
(1)7大参数
参数 | 描述 |
---|---|
corePoolSize | 线程池中的常驻核心线程池(new 不会创建,Execute 执行任务的时候创建,延迟加载,常驻线程池!!!) |
maximumPoolSize | 线程池中能容纳同时执行的最大线程数,此值必须>=1; |
keepAliveTime | 多余的空闲线程的存活时间,当前池中线程数量超过corePoolSize 时,当空闲时间达到keepAliveTime 时,多余线程会被销毁直到只剩下corePoolSize 个线程为止 |
unit | keepAliveTime 的单位 |
workQueue | 任务队列,被提交但尚未被执行的任务 |
threadFactory | 生成线程池中工作线程的线程工厂,用于创建线程,一般默认的就行 |
handler | 拒绝策略,当队列满了,并且工作线程>=线程池的最大线程(maximumPoolSize ),拒绝请求执行runnable 的策略 |
java.util.concurrent Class ThreadPoolExecutor 源码
(2)原理流程

②当调用`execute()`方法添加一个请求任务时,线程池会做出如下判断:
如果正在运行的线程数量小于corePoolSize
,那么马上创建线 程运行这个任务;
如果正在运行的线程数量大于或等于corePoolSize
,那么将这个任务放入队列;
如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize
,那么还是要创建非核心线程立刻运行这个任务;
如果队列满了且正在运行的线程数量大于或等于maximumPoolSize
,那么线程池会启动饱和拒绝策略来执行。
③当一个线程完成任务时,它会从队列中取下一个任务来执行。
④当一个线程空闲、超过一定的时间(keepAliveTime
)时,线程会判断:如果当前运行线程数大于corePoolSize
,那么这个线程就被停掉。当线程池的所有任务完成后,它最终会收缩到corePoolSize
的大小【自动调节池大小】。
四、手写线程池
线程池不允许使用Executors
创建,而是通过ThreadPoolExecutor
的方式,避免资源耗尽的风险!
FixedThreadPool
和singleThreadPool
允许请求队列的长度Integer.MAX_VALUE
,可能会堆积大量的请求(高并发高访问量)会导致OOM,(LinkedBlockingQueue
链表有界阻塞队列的长度2
的 31
次方 - 1 = 2147483648 - 1 = 2147483647
,运行程序的内存是有限的,所以提供的三个线程池不要使用,我们手写线程池!
(1)线程池的拒绝策略
等待队列已满,再也塞不下新任务,同时,线程池中的最大线程数也达到极限,这时就无法继续为新任务服务。我们就需要拒绝策略机制合理的处理这个问题!
(2)JDK内置拒绝策略种类
以下策略都实现了
RejectedExecutorHandle
接口!
拒绝策略 | 描述 |
---|---|
AbortPolicy (默认) | 直接抛出RejectedExecutionException 异常阻止系统正常运行 |
CallerRunsPolicy | “调用者运行”一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者(main 线程),从而降低新任务的流量【吞吐量最大】 |
DiscardOldestPolicy | 抛弃队列中等待最久的任务,然后把当前任务加人队列中尝试再次提交当前任务【适合时效性的系统】 |
DiscardPolicy | 该策略默默地丢弃无法处理的任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种策略 |
(3)手写线程池代码
package com.lindaxia.juc.demo;
import java.util.concurrent.*;
/**
* 线程池案例
* 拒绝策略(默认):AbortPolicy
* @author lindaxia
* @date 2019/11/1 18:20
*/
public class MyThreadPoolDemo {
public static void main(String[] args) {
ExecutorService threadPool = new ThreadPoolExecutor(
2, //核心线程数2
5, //最大线程数5
3L, //多余线程的空闲超时时间
TimeUnit.SECONDS, //单位秒
new ArrayBlockingQueue<Runnable>(3),//数组有界阻塞队列3个
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy() //默认拒绝策略,超出最大线程数就会报异常
);
try {
//3、5、8个任务,线程成功处理,9个任务已超出等待队列的容量就会抛异常
for (int i = 1; i <= 9; i++) {
threadPool.execute( //执行任务才会常见线程池
() -> {
System.out.println(Thread.currentThread().getName() + "\t号服务员提供服务");
}
);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPool.shutdown();//关闭线程池
}
}
}
打印结果1
测试结果2
#轻松一刻:
☝上述分享来源个人总结,如果分享对您有帮忙,希望您积极转载;如果您有不同的见解,希望您积极留言,让我们一起探讨,您的鼓励将是我前进道路上一份助力,非常感谢!我会不定时更新相关技术动态,同时我也会不断完善自己,提升技术,希望与君同成长同进步!
☞本人博客:https://coding0110lin.blog.csdn.net/ 欢迎转载,一起技术交流吧!