九.多线程复习笔记之线程池(面向大厂)

并发复习笔记之第九章(多线程并发之线程池)
想看后续请持续关注

以下来源有书籍 深入理解 JVM 虚拟机,java 并发编程的艺术,深入浅出多线程,阿里巴巴技术手册以及一些公众号 CS-Notes,JavaGuide,以及一些大厂高频面试题吐血总结,以及狂神说视频笔记,目的在于通过问题来复习整个多线程,已下是全部章节,觉得不错点个赞评论收藏三连一下,您的鼓励就是我继续创作的最大动力!!!!
一.多线程基础(面向面试总结超详细)
二.多线程基础之 volatile(面向面试吐血总结)
三.多线程基础之synchronized(面向面试,吐血整理)
四.多线程使用及线程间的通信(面向面试 吐血整理 超详细)
五.多线程进阶之锁(面向面试吐血整理)
六.多线程并发之容器
七.原子类和 CAS

9. 多线程并发之线程池 ⭐️

9.1 为什么要用线程池?

  • 降低资源消耗 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。

  • 提高响应速度 当任务到达时,任务可以不需要等到线程创建就能立即执行。

  • 提高线程可管理性 使用线程池可以进行统一分配、调优和监控。

9.2 使用线程池

9.2.1 线程池的创建

9.2.1.1 使用Executors 实现
  • Executors.newSingleThreadExecutor()

创建单条线程处理任务

  • Executor.newFixedThreadPool()

该⽅法返回⼀个固定线程数量的线程池。

  • Executor.CachedThreadPool()

可以无限扩大的线程池

  • Executors.ScheduledThreadPool()

实现周期性的线程调度

9.2.1.2 使用Executors 实现的缺点

说明:Executors 返回的线程池对象的弊端如下(阿里巴巴开发手册)

1)FixedThreadPool 和 SingleThreadPool:

允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM 。

2)CachedThreadPool 和 ScheduledThreadPool:

允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM 。

9.2.2 使用ThreadPoolExecutor 创建

9.2.2.1 线程池的七大参数

四个重要参数

  • corePoolSize 核心线程数量 = 银行每天上班的服务员
  • maximumPoolSize 最大线程个数 = 银行加班的服务员 + 每天上班
  • workQueue 阻塞队列 = 银行的等待的椅子
  • RejectedExecutionHandler 达到最大 = max + workqueue

三个不重要参数

  • keepAliveTime 等待时间 = 超过时间加班人员下班
  • threadFactory 构造Thread的方法,一般不变
  • TimeUnit unit 等待时间单位
9.2.2.2 线程池的增长策略
  • 可以通过以下代码去实践
public class Juc {
     
    public static void main(String[] args) throws InterruptedException {
      // 总数是6,必须要执行任务的时候,再使用!
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
                3,// 核心
                5,//固定最大
                3,//等待时间
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardOldestPolicy()
        );
        try {
      // 最大承载:Deque + max // 超过 RejectedExecutionException
                for (int i = 1; i <= 6; i++) {
     
                        threadPool.execute(()->{
     
                            System.out.println(Thread.currentThread().getName()+" ok");
                        }
                    );
                }
            } catch (Exception e) {
     
            e.printStackTrace();
        } finally {
     
            threadPool.shutdown();
        }
    }
}
  • 当线程数x,x<= 2(corePoolSize)每提交一个线程就创建一个线程(需要获取全局锁)
  • 当线程数x,2 <= x 每提交一个任务,将任务加入阻塞队列(大部分都是在执行这一步骤,不需要获取全局锁)
  • 当线程数x, 2 < x ,并且阻塞队列已经满了,启动非核心线程执行任务(需要获取全局锁)
  • 当线程数x,max = x 之后考虑拒绝策略

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T98VXpoS-1618567555351)(/Users/yazhouheilong/Library/Application Support/typora-user-images/截屏2021-04-16 16.58.38.png)]

9.2.2.3 线程池的拒绝策略

(当任务大于 max + queue)

  • AbortPolicy 直接抛弃,抛出异常
  • DiscardPolicy 直接丢弃,不抛出异常
  • CallerRunsPolicy 调用该execute的线程来执行(main线程)
  • DicardOldestPolicy 如果队列头部任务还在执行,抛弃队列的头部的任务,执行当前任务(可以看源码)
9.2.2.4 线程池的阻塞队列
  • ArrayBlockQueue 有界的阻塞队列 有界队列能增加系统的稳定性和预警能力(推荐使用 )
  • LinkedBlockQueue 无界的阻塞队列 maximumPoolSize可能没用 设置成无界队列,那么线程池的队列就会越来越多, 有可能会撑满内存,导致整个系统不可用

9.2.3 向线程池提交任务的两种方法区别

  • execute()

execute()方法用于不需要返回值的

  • submit()

submit() 有返回值,通过这个 future对象可以判断任务是否执行成功,并且可以通过future的get()方法来获取返回值

9.2.4 关闭线程池

  • shutdown()

9.2.5 配置线程池

暂略

你可能感兴趣的:(多线程,队列,java,多线程,面试,并发编程)