千万别从系统中创建线程, 看看从线程池中调用的线程的效率(理论篇)

本篇会加入个人的所谓鱼式疯言

❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言

而是理解过并总结出来通俗易懂的大白话,

小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.

可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!

在当今这个多核处理器成为标配的时代,如何高效地利用计算资源已成为软件开发中不可忽视的关键因素。随着应用程序变得越来越复杂,对并发处理的需求也日益增长。试想一下,在一个繁忙的服务器上,如果每一个新任务都创建一个新的线程来处理,那么系统将不堪重负——频繁的线程创建和销毁不仅消耗大量的时间和内存,还可能导致系统性能急剧下降。

前言

为了解决这一问题,并实现 更高效的资源管理线程池 的概念应运而生。线程池是一种用于 管理和复用一组预先创建好的线程 的方法,它通过预先创建一定数量的工作线程并将其 置于池中等待分配任务 ,从而 避免了频繁创建和销毁线程 带来的开销。

接下来的内容中,小编将带着小伙伴深入探讨 线程池的基本原理参数类型

目录

  1. 线程池的初识

  2. Java标准库中线程池的参数列表(重点)

一. 线程池的初识

1. 线程池的引入

我们知道,线程对于进程来说, 线程是 更微量的进程 ,开销更小, 但对于线程的本身来说虽然开销比较大。

但随着当前 并发编程的日益需求 越来越大, 频繁的从系统中 创建线程销毁线程的开销 还是相对而已比较大的。

所以我们就引入 “线程池” 的概念, 具体线程池是什么,该怎么理解,下面让小编具体来说明下吧

2. 线程池的概念以及理解

<1>. 线程池的概念

的概念好比一个地方,这个地方操作系统提前创建 好多线程 放在这个地方。

任务繁忙 的时候,我们就 从这个地方中调用这些线程

任务不繁忙 的时候,我们就把这些 线程重新调度回这个地方

而这个地方我们就成为 “线程池”

<2>. 线程池的理解

我们知道, 线程是操作系统进行 调度执行的基本单位

每次创建线程是从操作系统中 创建并且调度执行的

操作系统可以简单 分为 内核区 和 用户区。

内核区 是操作系统硬件的内层管理

用户区 是各种软件资源的任务执行

而操作系统面对多个软件的运行事务是十分繁忙的, 每创建一个 线程 去调度执行任务也不可控的。

好比现在小编要去银行去办理取钱事务, 就想柜台提出诉求, 但柜台说需要户口本复印件。

这时银行这边刚好有打印机

我有两种方式可以得到户口本的复印件

  1. 请柜台小姐姐帮我打印一下

  2. 自己动手打印

如果我们操作系统创建线程的, 就相当于请柜台小姐姐帮我 打印户口本 ,但柜台小姐姐的事务是 比较繁忙的 , 这个执行是 不可控的 , 我们并不知道柜台小姐姐什么时候完成事务来帮我打印户口本。

所以就像我们的操作系统创建线程一样,由于我们的操作系统是繁忙的,就有可能对于创建线程的这种需求,造成 一定的开销

而我们在线程池中去调度执行线程, 就好比上面的第二种方案,这是我们自己的去动手完成我们自己的需求,具体需要多久去完成,这些操作是由我们自己决定的, 这种行为是可控的。 所以 开销势必会少很多 , 也会 更轻量

二. Java标准库中线程池的参数列表(重点)

在我们 Java标准库 中提供一个很多类来创建我们的 线程池 来进行 任务的执行

其中我们重点讲解面试中常考的这个类,ThreadPoolExecutor (很多参数) ,

因为这个 参数比较多 , 也很麻烦,下面让小编仔细到来。

1. ThreadPoolExecutor

ThreadPoolExecutor 这个类来自于 java.util.concurrent 这个包。

在这里插入图片描述

在这个方法中, 我们有提供七个参数, 是 面试场合中HR比较喜欢问的话题

下面就让小编来 细细道来 吧。

2. corePoolSize 和 maximumPoolSize

corePoolSize: 线程核心数, 就是说在这个线程中都必须有的元老级别的线程, 在创建这个线程池是就至少有这些线程。

在我们的线程池中,有两类线程: 核心线程和非核心线程

当我们 任务繁忙 时, 核心线程和非核心线程都会 被创建出来一起工作

当我们 任务不繁忙 时, 只需要核心线程来工作, 而非核心线程就会被销毁

所以一定会 执行的是核心线程,任务繁忙被销毁的 , 就是我们的非核心线程

maximumPoolSize : 最大线程数

而我们的 最大线程数= 核心线程数 + 非核心线程数。

而真正限制 最大线程数 的主要因素就是我们的 CPU的核心数

鱼式疯言

核心线程: 好比我们一个公司的正式员工,无论公司是否繁忙, 公司都是需要的, 不会随意开除正式员工。

非核心线程: 好比我们一个公司的实习生, 只有当公司繁忙时,实习生才会 被录用 , 而 当公司不繁忙时 , 实习生就会 被开除

3. keepAliveTime 和 unit

一个线程是 有可能没有任务去工作 ,这时操作系统就需要考虑要不要 回收释放这个线程资源, 就需要考虑这个线程需要 空闲的最大时间

keepAliveTime : 允许空闲的最大时间, 一旦 实际的空闲时间 超过这个 允许空闲的最大时间 ,这个线程就会 被释放

unit: 允许空闲的最大时间的单位设置, 这里的单位设置就有很多种: 毫秒,妙, 日,月,年等…

鱼式疯言

允许空闲的最大时间 : 就好比一个实习生需要去不断的去工作,如果这个实习生没有任务可做,空闲下来了 ,一旦超过这个允许空闲的最大时间,公司就会把这个实习生给开除掉。

4. workQueue

在我们线程中,不同的线程可能执行不同的任务, 而这些任务该怎么存放和管理呢?

于是我们就借助了一个特殊的队列: 阻塞队列

workQueue:工作队列:对于这个队列本质上是一个Running类型的阻塞队列用于我们工作队列: BlockingQueue workQueue = new BlockingQueue , 这个队列我们就需要把需要完成的任务都存放在这个 工作队列 中, 进行工作。

鱼时疯言

此处的队列:

  1. 队列的大小: 程序员自己定义Size

  2. 队列的类型: 程序员自己决定

5. threadFactory

对于我们线程池的初始化, 我们可能会想到构造方法, 但是 构造方法也可能会出现问题 , 于是我们就引入一种设计模式(套路) : 工厂设计模式 来进行补充 我们构造方法对于线程池初始化的不足

构造方法的问题:

因为构造方法会对于 类型不同,数量不同 的方法会发生 重载

而对于 类型相同,数量相同的构造方法 来说,就不会发生 重载 ,就无法实现我们 多个参数的初始化

线程工厂: 在我们线程工厂中设计了一种普通的 成员方法(静态方法) 来通过执行我们的方法对线程池中的 成员变量 进行 初始化操作 , 从而解决构造方法重载的不足问题

鱼式疯言

有图有真相

千万别从系统中创建线程, 看看从线程池中调用的线程的效率(理论篇)_第1张图片

6. handler (重点掌握)

对于线程过多, 执行的任务超出了我们的 最大限度线程池 会通过 阻塞等待的操作防止任务过满 吗?

答案是 不会的 .

hander: 拒绝策略:对于任务过满,任务加载过多的情况, 我们的会根据不同的情况采用 4 种不同的策略 来安排我们下一步该怎么操作。

4种不同的策略:

千万别从系统中创建线程, 看看从线程池中调用的线程的效率(理论篇)_第2张图片

<1>. AbortPolicy

这种处理方式就比较简单粗暴,当 任务过满 时, 添加任务时就会 直接抛出异常, 相当于这个无论是当前讲要执行的任务,还是之前的任务都无法执行,程序直接中断

<2>. CallerRunspolicy

这种处理方式就比较友好,当任务过满时, 线程池会 拒绝执行新增加的任务 ,而是按照常规任务 继续执行

<3>. DifcardOldestPolicy

当任务过满时,这个方式就是把最老的那个任务给踢掉,让 新的任务添加进来执行。 这样保证任务 不会出现过满 的情况,也能执行到 新的任务

<4>. DiscardPolicy

当任务过满时, 这个方法就是在 任务队列 中, 把 最新的那个任务给踢掉

注意: 在任务队列中踢掉的任务,是 其他线程也不能执行到的

鱼式疯言

给小伙伴举个生活中的栗子吧

有一天小爱同学和我同时写博客, 她突然跑过来说,让我过去帮她写一下,有些东西不是很懂, 但我现在也要写博客啊,那就会采取下面4 种策略。

  1. 抛出异常: 我直接告诉小爱同学,今天好累啊,我都有点不想写博客了, 于是小爱同学的博客没有帮忙写,小编自己的博客同时也没写,新的任务和之前的任务都不执行 , 直接摆烂了

  2. 拒绝执行: 我告诉小爱同学,你先自己搞搞呗,我这边自己还得写博客呢 ,这样新的任务我 拒绝执行 了, 我还是 继续执行我自己的任务她去执行她自己的任务。

  3. 踢掉老任务: 小爱同学找我帮忙,于是我就把任务中最老的任务给踢掉,直接去执行她的那个新任务了

  4. 踢掉新任务: 小爱同学找我帮忙,我就和小爱同学说,你先别写,先看我平常是怎么写的,于是我就把这个新任务都踢掉,大家不去执行这个新的任务

总结

  • 线程池的初识: 线程池对于线程开销的认识以及背后更好去调度的原理理解。
  • . Java标准库中线程池的参数列表(重点): 认识到对于 ThreadPoolExecutor 这个类的认识是来源于 java.util.concurrent这个包, 并且熟悉了七个参数的用法,理解了工厂设计模式,和拒绝策略的4种不同方式。

如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正

希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力

千万别从系统中创建线程, 看看从线程池中调用的线程的效率(理论篇)_第3张图片

你可能感兴趣的:(踏寻,JavaEE,之谜,计算机八股文知识study,java,开发语言,java-ee,spring,boot,spring,jvm,java-consul)