线程池使用及优势
线程池做的工作主要是控制运行的线程的数量,处理过程中将任务放入队列,然后在创建后启动这些任务,如果线程数据超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行
他的主要特点为:线程复用 控制最大并发数 管理线程
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁的消耗
第二:提高响应速度。当任务到达时任务可以不需要的等到线程创建就能立即执行。
第三:提高线程的可管理性。线程时稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

1.1 常用的线程池
-
newFixedThreadPool 执行长期的任务,性能好很多
-
newSingleThreadExecutor 一个任务一个任务执行的场景
-
newFixedThreadPool 执行很多短期异步的小程序或者负载较轻的服务器
1.2 线程池七大参数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ydbpp8vU-1644397721463)(/Users/chensihao/Library/Application Support/typora-user-images/image-20220209133954431.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tswLn9BF-1644397721464)(/Users/chensihao/Library/Application Support/typora-user-images/image-20220209140847725.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RrN3ozog-1644397721464)(/Users/chensihao/Library/Application Support/typora-user-images/image-20220209141705719.png)]
1.3 JVM拒绝策略
当最大线程池已满,阻塞队列已满,线程池会使用拒绝策略
-
Abort(默认):直接抛出RejectExecutorException异常阻止系统正常运行
-
CallerRunsPolicy: 调用者运行一种机制,该策略及不回抛弃任务,也不会抛出异常,而是将某些任务回退到调用者(由调用者来执行),从而降低新任务的流量。
-
DiscardOldestPolicy: 抛出队列中等待最久的任务,然后把当前任务加入队列中尝试再次提示当前任务
-
DiscardPolicy: 直接丢弃任务,不予任务处理也不抛出异常。如果允许任务丢失,这是最好的一种方案
线程池在实际中使用哪一个
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,避免资源耗尽的风险。
说明:Executor放回的线程池对象的弊端如下:
1)Fixed ThreadPool和SingleThreadPool:
允许的请求队列的长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
2)CachedThreadPool和ScheduleThreadPool
允许的创建线程数量为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致OOM。
1.4 手写线程池改造和拒绝策略
public class ExecutorPoolThreadDemo {
public static void main(String[] args) {
ExecutorService executor = new ThreadPoolExecutor(
2,//核心处理数
5, // 最大线程数
1,// 空闲时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(3),// 创建阻塞队列
Executors.defaultThreadFactory(), // 默认线程工程
new ThreadPoolExecutor.AbortPolicy()); // 拒绝策略
try{
for (int i = 0; i < 20; i++) {
executor.execute(()->{
System.out.println(Thread.currentThread().getName()+" 办理业务");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
executor.shutdown();
}
}
}
1.5 合理配置线程池线程数
CPU密集型
CPU密集的意思是该任务需要大量的运算,而没有阻塞,CPU一致全速运行
CPU密集任务只有在真正的多核CPU上才可能得到加速(通过多线程)
而在单核CPU上无论你开几个模拟的多线程该任务都不可能得到加速,因为CPU总的运算能力就那些。
CPU密集型任务配置尽可能少的线程数量:一般公式:CPU核数 + 1个线程的线程池
IO密集型
-
由于IO密集型任务线程并不是一直执行任务,则应配置尽可能多的线程,如CPU核数 * 2
-
IO密集型,即该任务需要大量的IO,即大量的阻塞,在单线程上运行IO密集型的任务会导致大量的CPU浪费在等待。所以在IO密集型任务中使用多线程可能大大的加速程序运行,即使在单核CPU上,这种加速主要就是利用了被浪费掉的阻塞时间。
IO密集型时,大部分线程都阻塞,故需多配置线程数
参考公式:CPU核数 /(1 - 阻塞系数) (阻塞系统在0.8~0.9)
比如8核CPU:8 /(1 -0.9 )= 80个线程数
1.6 死锁编码及定位分析
死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力干涉那它们将无法推进下去,如果系统资源充足,进程的资源请求都能狗得到满足,死锁的出现可能性就很低,否则就会因争夺有限的资源而陷入死锁。

1. 线程死锁案例
class HoldLockThread implements Runnable{
private String lockA;
private String lockB;
public HoldLockThread(String lockA, String lockB) {
this.lockA = lockA;
this.lockB = lockB;
}
@Override
public void run() {
synchronized (lockA){
System.out.println(Thread.currentThread().getName()+" 自己持有"+lockA+" 尝试获得"+lockB);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB){
System.out.println(Thread.currentThread().getName()+" 自己持有"+lockB+" 尝试获得"+lockA);
}
}
}
}
public class DeadLockDemo {
public static void main(String[] args) {
String lockA = "lockA";
String lockB = "lockB";
new Thread(new HoldLockThread(lockA,lockB)).start();
new Thread(new HoldLockThread(lockB,lockA)).start();
}
}
-
解决死锁
# 抓内存,看底层源码 # 查看java运行的程序 jps -l 2833 com.csh.thread.CallableDemo 3393 sun.tools.jps.Jps 1890 st 691 3323 org.jetbrains.jps.cmdline.Launcher 3324 com.csh.thread.DeadLockDemo # 分析线程情况 jstack 进程ID Java stack information for the threads listed above: =================================================== "Thread-1": at com.csh.thread.HoldLockThread.run(DeadLockDemo.java:26) - waiting to lock <0x000000076ac19858> (a java.lang.String) - locked <0x000000076ac19890> (a java.lang.String) at java.lang.Thread.run(Thread.java:748) "Thread-0": at com.csh.thread.HoldLockThread.run(DeadLockDemo.java:26) - waiting to lock <0x000000076ac19890> (a java.lang.String) - locked <0x000000076ac19858> (a java.lang.String) at java.lang.Thread.run(Thread.java:748) Found 1 deadlock.

