多线程(二):线程池

线程池基础笔记

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

一、线程池基础

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

1、什么是线程池

  • 线程池是一种基于池化思想管理线程的工具
  • image-20220707103557194

2、为什么要使用线程池

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

3、线程池如何执行任务

  • image-20220707103632942

4、线程池的好处

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

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

阿里巴巴开发手册

image-20220707103733610

  • 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)

  • 必须参数

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

    • (自定义线程工厂)
    • (线程拒绝策略)
image-20220707103826204

image-20220707103840004

线程池形象化

image-20220707104114781

等待任务队列形象化

image-20220707104213985
  • 任务队列一般用
    • ArrayBlockingQueue
    • LinkedBlockingQueue

线程工厂

image-20220707104339665 image-20220707104350344 image-20220707104401295

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

image-20220707104436682

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

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

创建线程池的方式

image-20220707104611495

image-20220707104642378

风险

image-20220707104837944

  • FixedThreadPool:固定大小的线程池
    • image-20220707105141346
    • image-20220707104728512
    • 默认使用的是 LinkedBlockingQueue,然后其容量默认为 Integer 的最大值
    • 有资源耗尽,内存被爆掉的风险
  • SingleThreadExecutor:单个线程的线程池
    • image-20220707104922233
    • 默认使用的是 LinkedBlockingQueue,风险和 FixedThreadPool 一样
  • CachedThreadPool:可缓存的线程池
    • image-20220707105035220

总结

image-20220707105118759

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

  • excute 只适合提交 Runnable 无返回值的任务
  • submit 适用范围较广
image-20220707105244809 image-20220707105320512

总结区别

image-20220707105624914

image-20220707105642297

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

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

Future对象

  • 是一个接口
  • image-20220707105933164
  • image-20220707105958280

阻塞式

image-20220707110118863 image-20220707110037395

定时式

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

image-20220707110249415

2. Futrue取消任务:Cancle方法

image-20220707110531244

image-20220707111424911

image-20220707110604252

Cancle 方法的 3 种情况

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

image-20220707110948386

取消正在执行中的线程

  • 参数为 false

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

    • 抛出取消成功的异常

    • 但任务并非立马结束的

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

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

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

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

三、任务拒绝策略

image-20220707111459264

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

image-20220707111519980

使用

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

  • image-20220707112103263

四、关闭线程池

1. 关闭线程池:shutDown

该方法执行后:

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

2. 关闭线程池:shutDownNow

该方法执行后:

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

与 shutdown 的区别

image-20220707112631696

五、线程池深入探究

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

状态

image-20220707112818826

image-20220707112929493

生命周期

image-20220707113858782

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

image-20220707130819737

excute方法详情

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

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

1. 如何批量执行任务

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

image-20220707154214220

  • invokeAll
    • 按集合中任务顺序执行任务
    • 也是按顺序返回执行结果
    • image-20220707154246247
  • 超时的invokeAll & invokeAny
    • image-20220707154541524
    • 时间到了之后
      • 未完成的任务直接全部取消
      • 已完成的任务,结果全部返回给调用者
  • invokeAny
    • 执行批量任务,返回最先完成的任务的执行结果
    • 然后取消未完成的任务

image-20220707155138870

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

ScheduledThreadPoolExecuter

image-20220707155307290

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

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

  • scheduleAtFixedRate

    • image-20220707162031017
  • scheduleWithFixedDelay

    • image-20220707162014110
  • 方法内的参数

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

    • image-20220707162655951
    • image-20220707162711112

七、线程池扩展

1. Forkjoin框架

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

image-20220707163006606

image-20220707162933052

2. 使用 ForkJoinPool

image-20220707163947055

image-20220707164013403

使用例子

任务:从 1 加到 100

image-20220707164053426

3. 如何使用 ExecutorCompletionService

  • 返回结果采用:执行优先原则,即先执行完的先返回
  • image-20220707164653539
  • image-20220707164846909

image-20220707164913596

4. 如何监控线程池

线程池的监控点

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

image-20220707165015764

image-20220707165156095

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值