多线程(二):线程池

线程池基础笔记

学习视频地址:https://www.bilibili.com/video/BV1wh411e7nd?share_source=copy_web

一、线程池基础

1. 什么是线程池?为什么要使用线程池?

1、什么是线程池

  • 线程池是一种基于池化思想管理线程的工具
  • 多线程(二):线程池_第1张图片

2、为什么要使用线程池

  • 一个线程对应一个任务
  • 如果要执行多个任务,则需创建多个线程
  • 传统的方法,线程不能复用,一次只执行一个任务就被销毁了

3、线程池如何执行任务

  • 多线程(二):线程池_第2张图片

4、线程池的好处

  • 降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗
  • 提高响应速度:当有任务时,任务可以不需要等到线程创建就能立即执行
  • 提高线程的可管理性:线程池可以进行统一的分配,调优和监控

2. 如何使用原生方式创建线程池

阿里巴巴开发手册

多线程(二):线程池_第3张图片

  • ThreadPoolExecutor(int ,int ,long ,TimeUnit ,BlockingQueue)

  • ThreadPoolExecutor(int ,int ,long ,TimeUnit ,BlockingQueue ,ThreadFactory)

  • ThreadPoolExecutor(int ,int ,long ,TimeUnit ,BlockingQueue ,RejectedExecutionHandler)

  • ThreadPoolExecutor(int ,int ,long ,TimeUnit ,BlockingQueue ,ThreadFactony , RejectedExecutionHandler)

  • 必须参数

    • 核心线程数
    • 最大线程数
    • 空闲非核心线程存活时间
    • 时间单位
    • 线程等待队列容器
  • 可选参数

    • (自定义线程工厂)
    • (线程拒绝策略)
多线程(二):线程池_第4张图片

多线程(二):线程池_第5张图片

线程池形象化

多线程(二):线程池_第6张图片

等待任务队列形象化

多线程(二):线程池_第7张图片
  • 任务队列一般用
    • ArrayBlockingQueue
    • LinkedBlockingQueue

线程工厂

多线程(二):线程池_第8张图片 多线程(二):线程池_第9张图片 多线程(二):线程池_第10张图片

任务拒绝策略(后续详解)

多线程(二):线程池_第11张图片

3. 有风险,需慎用的创建方法

  • FixedThreadPool:固定大小的线程池
  • SingleThreadExecutor:单个线程的线程池
  • CachedThreadPool:可缓存的线程池

创建线程池的方式

多线程(二):线程池_第12张图片

多线程(二):线程池_第13张图片

风险

多线程(二):线程池_第14张图片

  • FixedThreadPool:固定大小的线程池
    • 多线程(二):线程池_第15张图片
    • 多线程(二):线程池_第16张图片
    • 默认使用的是 LinkedBlockingQueue,然后其容量默认为 Integer 的最大值
    • 有资源耗尽,内存被爆掉的风险
  • SingleThreadExecutor:单个线程的线程池
    • 多线程(二):线程池_第17张图片
    • 默认使用的是 LinkedBlockingQueue,风险和 FixedThreadPool 一样
  • CachedThreadPool:可缓存的线程池
    • 多线程(二):线程池_第18张图片

总结

多线程(二):线程池_第19张图片

4. 线程提交方式:excute 和 submit 的区别

  • excute 只适合提交 Runnable 无返回值的任务
  • submit 适用范围较广
多线程(二):线程池_第20张图片 多线程(二):线程池_第21张图片

总结区别

多线程(二):线程池_第22张图片

多线程(二):线程池_第23张图片

二、获取任务执行结果:Future 类

1. Future获取任务执行结果(阻塞式和定时式)

Future对象

  • 是一个接口
  • 多线程(二):线程池_第24张图片
  • 多线程(二):线程池_第25张图片

阻塞式

多线程(二):线程池_第26张图片 多线程(二):线程池_第27张图片

定时式

超时为得到执行结果则抛出异常,捕获该异常可执行其他任务。

多线程(二):线程池_第28张图片

2. Futrue取消任务:Cancle方法

多线程(二):线程池_第29张图片

image-20220707111424911

多线程(二):线程池_第30张图片

Cancle 方法的 3 种情况

  • 取消未执行的任务
  • 取消已完成的任务
  • 取消正在执行的任务

多线程(二):线程池_第31张图片

取消正在执行中的线程

  • 参数为 false

    • 抛出取消成功的异常
    • 但任务还是会继续执行完
    • 但 get 是获取不到东西了的,会抛异常
  • 参数为 true

    • 抛出取消成功的异常

    • 但任务并非立马结束的

    • 需要响应中断线程的指令

      • 即,如果任务中有死循环,则无法响应中断指令

      • 这样响应线程中断指令即可成功地真正意义上的取消

      • // 当线程没被中断时
        while (!Thread.interrupted()) {
            // 递增i
            i++;
        }
        

三、任务拒绝策略

多线程(二):线程池_第32张图片

这四个类,都实现了同一个接口

多线程(二):线程池_第33张图片

使用

创建线程池时,传入该参数即可

  • 多线程(二):线程池_第34张图片

四、关闭线程池

1. 关闭线程池:shutDown

该方法执行后:

  • 线程池及任务队列不允许添加新任务
  • 会继续执行完线程池及任务队列中还未执行完的任务

2. 关闭线程池:shutDownNow

该方法执行后:

  • 线程池不允许添加新任务
  • 会给线程池中的任务发送中断指令
  • 能响应中断指令的任务将会被中断
  • 线程池关闭后,返回任务队列中的任务:即等待中未执行的任务
  • 返回任务队列中的任务给父线程,父线程可以选择继续执行或不操作不接收等等

与 shutdown 的区别

多线程(二):线程池_第35张图片

五、线程池深入探究

1. 线程池状态及生命周期

状态

多线程(二):线程池_第36张图片

多线程(二):线程池_第37张图片

生命周期

多线程(二):线程池_第38张图片

2. 线程池是怎样执行任务的

多线程(二):线程池_第39张图片

excute方法详情

多线程(二):线程池_第40张图片
  • addWorker( 任务内容 , 是否做核心线程)
    • addWorker(null, false):添加一条非核心线程。
    • 添加后会自动去接收任务队列中的任务执行。
  • ctl.get( ) :获取线程池状态、线程数
  • isRunning( c ):判断线程池是否在运行,即线程池是否被关闭或者停止。
  • workerQueue.offer( command ):添加任务到任务队列中。
  • remove( command ):移除任务。
  • reject( command ):拒绝任务。
  • 多线程(二):线程池_第41张图片

六、线程池处理任务的多种情况

1. 如何批量执行任务

可以看出,能批量执行的,只能是 Callable 任务!

多线程(二):线程池_第42张图片

  • invokeAll
    • 按集合中任务顺序执行任务
    • 也是按顺序返回执行结果
    • image-20220707154246247
  • 超时的invokeAll & invokeAny
    • 多线程(二):线程池_第43张图片
    • 时间到了之后
      • 未完成的任务直接全部取消
      • 已完成的任务,结果全部返回给调用者
  • invokeAny
    • 执行批量任务,返回最先完成的任务的执行结果
    • 然后取消未完成的任务

多线程(二):线程池_第44张图片

2. 如何执行定时、延时任务?

ScheduledThreadPoolExecuter

多线程(二):线程池_第45张图片

  • 调度线程池
  • image-20220707161057911
  • image-20220707161210719
  • image-20220707161256440

3. 如何执行周期、重复性任务?

  • scheduleAtFixedRate

    • image-20220707162031017
  • scheduleWithFixedDelay

    • image-20220707162014110
  • 方法内的参数

    • 任务
    • 执行前延时时间
    • 固定时间 / 间隔时间
    • 时间单位
  • 区别

    • 多线程(二):线程池_第46张图片
    • image-20220707162711112

七、线程池扩展

1. Forkjoin框架

ForkJoin 是一个把大任务分割成若干个小任务,再对每个小任务得到的结果进行汇总,得到大任务结果的框架。

多线程(二):线程池_第47张图片

多线程(二):线程池_第48张图片

2. 使用 ForkJoinPool

多线程(二):线程池_第49张图片

多线程(二):线程池_第50张图片

使用例子

任务:从 1 加到 100

多线程(二):线程池_第51张图片

3. 如何使用 ExecutorCompletionService

  • 返回结果采用:执行优先原则,即先执行完的先返回
  • 多线程(二):线程池_第52张图片
  • 多线程(二):线程池_第53张图片

多线程(二):线程池_第54张图片

4. 如何监控线程池

线程池的监控点

  • 线程的变化情况
  • 任务的变化情况

多线程(二):线程池_第55张图片

多线程(二):线程池_第56张图片

你可能感兴趣的:(Java基础,java,开发语言)