栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JDK线程池的总结

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JDK线程池的总结

线程池
    • 1. 概述
      • 1.1 背景/引入
      • 1.2 什么是线程池
      • 1.3 优点
      • 1.4 类图
    • 2. 线程池状态
    • 3. ThreadPoolExecutor构造(7大参数)
        • 参数说明:
        • 工厂方法:
        • 运行流程:
        • 救急线程和核心线程的区别 ?
    • 4. 阻塞队列
    • 5. JDK线程池的拒绝策略
    • 6. 提交任务
    • 7. 关闭线程池

1. 概述 1.1 背景/引入

线程是系统资源,每创建新的线程会占用资源,且创建和销毁对象开销较大;
高并发时,如果为每个任务都创建新的线程,则对内存占用太大,可能会内存溢出;
线程池技术的引入,就是为了解决这一问题.

1.2 什么是线程池

一个线程集合用来控制线程的数量,会先创建一定数量的线程放入空闲队列中,当任务来了之后就给任务分配线程去执行;
当线程被任务占满后,会将任务放到阻塞队列排队,等待其他线程执行完毕,再从队列中取出任务来执行;
如果选的是有界队列,当阻塞队列满了,再来新的任务,就会创建救急线程;
当救急线程也满了,会执行拒绝策略;

池化技术的思想主要是为了减少每次获取资源的消耗,提⾼对资源的利用率。

1.3 优点

降低资源消耗:通过重复利⽤已创建的线程降低线程创建和销毁造成的消耗,提高线程的重用性。
提高响应速度:当任务到达时,任务可以不需要的等到线程创建就能⽴即执⾏。
提高线程的可管理性:线程是稀缺资源,如果⽆限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使⽤线程池可以进⾏统⼀的分配,调优和监控。

1.4 类图


ExecutorService是线程池的基本接口,提供了提交任务、关闭线程池的方法;
ScheduledExecutorSerivce是ExecutorService的子接口,在ExecutorService基础上新增了任务调度的功能,可以定时执行任务;
ThreadPoolExecutor是ExecutorService的基础实现类;
ScheduledThreadPoolExecutor继承于ThreadPoolExecutor, 是带任务调度功能的实现类;

2. 线程池状态

3. ThreadPoolExecutor构造(7大参数)

参数说明:

由于构造方法参数太多,初学者不易掌握,所以有Executor工具类提供了工厂方法来创建线程池;

工厂方法:
  1. newFixedThreadPool(int nThreads):创建固定大小的线程池,并直接返回线程池对象;



特点:
1.参数线程数n是核心线程数,救急线程数为0 ;
2.阻塞队列是无界的,可以放任意数量的任务(救急线程的前提是选择了有界队列)

  1. newSingleThreadPool():创建单线程线程池
    返回的是装饰器,只有ExecutorService的方法,不能使用ThreadPoolExecutor的方法;
    使用场景:
    希望任务排队串行执行;线程数固定为1,任务数多余1时,会放入无界队列排队;
    和自己创建一个任务的区别:
    自己创建的一个线程如果任务失败了没有任何补救措施,而线程池还会创建新的线程,保证线程池的正常工作
运行流程:

execute() 添加任务到线程池执行,当核心线程数不够时,则将任务放到阻塞队列中排队:
当任务超过了阻塞队列大小时,再来任务,就会创建maximumPoolSize - corePoolSize 个的救急线程来运行任务(前提是选择有界队列);
救急线程的前提是选择了有界队列;若队列是无界队列,即没有容量限制的队列,则不会创建救急线程;

救急线程和核心线程的区别 ?

救急线程有生存时间,类似临时工,任务完毕救急线程就被销毁;而核心线程执行完任务依然保留在线程池中;

当线程到达maximumPoolSize最大线程数仍有新任务时,即核心线程和救急线程都被任务占完了,才会执行拒绝策略;

4. 阻塞队列

阻塞队列一般用于生产者、消费者场景,生产者往队列中添加元素,消费者从队列取线程;
在线程池中,通过阻塞队列来实现任务的生产和消费功能;
当队列为空,会阻塞消费者;当队列满了,会阻塞生产者;

阻塞队列有一个非常重要的属性,那就是容量的大小,分为有界和无界两种。

通常,阻塞队列是有界的,例如 ArrayBlockingQueue 如果容量满了,也不会扩容,所以一旦满了就无法再往里放数据了。(救急线程的前提是选择有界队列 !)
无界队列意味着里面可以容纳非常多的元素,例如 LinkedBlockingQueue 的上限是 Integer.MAX_VALUE,约为 2 的 31 次方,是非常大的一个数,可以近似认为是无限容量,因为我们几乎无法把这个容量装满。

缺点:无界队列存在比较大的潜在风险,如果在并发量较大的情况下,线程池中可以几乎无限制的添加任务,容易导致内存溢出的问题!

5. JDK线程池的拒绝策略


AbortPoliocy:抛出异常(默认)
CallerRunsPolicy:让调用线程(提交任务的线程)直接执行此任务
DiscardPolicy:放弃本次任务
DiscardOldestPolicy:放弃最早的任务,当前任务取而代之

6. 提交任务
  1. execute:
    参数是Runable类型,无返回结果;

  2. submit:
    参数是Callable,实现Callable的线程是有返回值的;
    submit方法会返回Future对象,可以用来判断任务是否执行成功;
    FutureTask用来在主线程中接收线程池中返回的结果;调用FutureTask对象的**get()**方法获取返回值;

  3. invokeAll:
    接收一个集合,执行集合中所有的任务,
    返回LIst集合,集合中是Future,

  4. invokeAny:
    不会执行所有任务,而是找到最先执行的任务;
    只要集合中有一个任务执行成功,就把整个任务的结果作为返回最终的结果返回,其他的取消;

7. 关闭线程池
  1. shutdown:
    不会接收新的任务,但会处理阻塞队列中剩余任务;

  2. shutdownNow:
    将线程池的状态变成stop,即不仅不接受新任务,还会将正在执行的任务停下来 !
    正在执行的任务会用interrupt方法打断 ! 并将任务返回

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1020099.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号