【多线程】震惊!这是我见过最详细的线程池的讲解

线程池的基本概念

一.什么是线程池.

ThreadPoolExecutor是Java中的一个线程池执行器,它可以管理和调度多个线程,使得多个任务可以并发执行,从而提高程序的执行效率。线程池执行器可以控制线程的数量、执行方式、优先级等,避免了线程的频繁创建和销毁,从而减少了系统开销。简单来说就是,提前把要用的对象创建好,用完对象不急着释放,留下来以备下一次使用
ThreadPoolExecutor 本身用起来比较复杂.因此标准库还提供了另一个版本,把ThreadPoolExecutor给封装了一下.—>Executors 工厂类.通过这个类创建出不同的线程池对象.(在内部把ThreadPoolExecutor创建好了并且设置了不同的参数)

二.为什么要引入线程池?

为了解决进程频繁的创建销毁所带来的资源消耗而引入线程~~当线程过于频繁的创建和销毁的时候,此时消耗的资源也就不能忽视了,此时解决这个问题的办法有两种:
  • 1.引入轻量级线程,也叫"纤程/协程"…协程的本质就是程序员在用户态代码中进行调度,不是靠内核的调度器调度.
  • 使用线程池,相当于牺牲了空间提高了效率.
.为什么从线程池获取线程,要比在系统内核中申请创建线程更高效?

基本结论:如果一个工作,自己可以完成,那么一定是更可控,更高效的; 反之,让别人来完成,那么会不可控,更低效.
因此.通过系统申请线程,就需要内核来完成.从线程池中取线程是纯用户态代码,因此从线程池取线程会更加高效.

三.线程池的构造方法(此处只介绍参数最多的那一种)

ThreadPoolExecutor(int corePoolSize,int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler);

  • ①.corePoolSize 核心线程数—>一个线程池中至少有的线程数.
  • ②.maximumPoolSize 最大线程数—>一个线程池里最多有几个线程.
  • ③.keepAliveTime 除了核心线程,空闲的线程所能存在的最长时间.
  • ④.TimeUnit 时间单位
    TimeUnit.DAYS:天
    TimeUnit.HOURS:小时
    TimeUnit.MINUTES:分
    TimeUnit.SECONDS:秒
    TimeUnit.MILLISECONDS:毫秒
    TimeUnit.MICROSECONDS:微妙
    TimeUnit.NANOSECONDS:纳秒
  • ⑤.BlockingQueue 阻塞队列,线程池中可以含有多个任务.
    ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
    LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。
    SynchronousQueue:一个不存储元素的阻塞队列,即直接提交给线程不保持它们。
    PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
    DelayQueue:一个使用优先级队列实现的无界阻塞队列,只有在延迟期满时才能从中提取元素
    LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。与SynchronousQueue类似,还含有非阻塞方法。
    LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
  • ⑥.ThreadFactory 线程工厂–>通过这个工厂来创建线程
    工厂模式是一种常见的设计模式:通过专门的工厂类/工厂对象来创建线程.==>展开来说就是通过静态方法(也可以是普通方法)来封装new操作在方法内部,通过设定不同的属性来完成对象的创建.
  • ⑦.RejectedExecutionHandler 拒绝策略–>在一个线程池中有一个阻塞对列,当队列的任务满了以后,需要制定一个拒绝策略.
    在这里插入图片描述
    1.拒绝策略一: 抛出RejectedExecutionException异常.此时新的任务没法进行了,并且旧的任务也没法进行了.满了之后再加,原来的和新加的任务都没办法进行了.
    2.拒绝策略二: 新的任务有添加任务的线程执行.新的任务会执行,但是不是线程池执行,而是添加新任务的线程执行.
    3.拒绝策略三: 丢弃最老的任务,执行新的任务.新的线程加入执行,把最早加入的线程抛弃
    4.拒绝策略四: 无视新的线程,按原来的线程继续执行.新的线程直接无视,按原来的线程执行

四. 线程池中线程数目的设定为多少合适?

不同的程序,需要设置的线程数目是不一样的,需要具体问题具体分析.

  • 看一个线程是cpu密集型任务(这个线程大部分时间都在cpu上运行(进行计算~~)),还是io密集型任务(这个线程大部分时间都是在等待IO,不去cpu上执行)
  • 如果一个进程中的所有线程都是cpu密集型,每个线程的所有时间都是在cpu上执行,此时,线程池中线程的数目的设定不能超过N(cpu逻辑核心数)
    如果一个进程中的所有线程都是IO密集型,每个线程的大部分时间都是在等待IO,cpu消耗很少,此时,线程池中的线程数目的设定可以远远超过N(cpu的逻辑核心数).
  • 但在实际开发中,很难直接对线程池中的数目进行估算…此时更合适的做法,**就是通过实验/测试找到合适的线程数目.**尝试给线程池设定不同的线程数目,分别进行性能测试.衡量每种线程数目下,总的时间开销,和系统资源占用的开销,找到这两者之间的合适值!!

五.创建线程池的七种方式.

  • Executors.newFixedThreadPool():fixed汉语意思是固定的, 创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;
  • Executors.newCachedThreadPool():cache的意思是缓存, 创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • Executors.newSingleThreadExecutor():创建单个线程数的线程池,它可以保证先进先出的执行顺序;
  • Executors.newScheduledThreadPool():创建一个定长线程池,支持定时及周期性任务执行
  • Executors.newSingleThreadScheduledExecutor():创建一个单线程的支持定时及周期性任务执行的线程池;
  • Executors.newWorkStealingPool():创建一个抢占式执行的线程池(任务执行顺序不确定)
  • 24
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值