面试(03)————多线程和线程池
一、多线程
1、什么是线程?线程和进程的区别?
2、创建线程有几种方式 ?
3、Runnable 和 Callable 的区别?
4、如何启动一个新线程、调用 start 和 run 方法的区别?
5、线程有哪几种状态以及各种状态之间的转换?
6、线程相关的基本方法?
7、 wait()和 sleep()的区别?
二、线程池
1、为什么需要线程池
2、线程池的分类(高薪常问)
3、核心参数(高薪常问)
4、线程池的原理(高薪常问)
5、拒绝策略
6、如何关闭线程池
7、线程池中阻塞队列的作用?为什么是先添加列队而不是先创建最
大线程?
8、线程池中线程复用原理
一、多线程
1、什么是线程? 线程和进程的区别?
线程:是进程的一个实体,是 cpu 调度和分派的基本单位,是比进程更小的可以独立运行的基本单位。进程:具有一定独立功能的程序关于某个数据集合上的一次运行活动,是操作系统进行资源分配和调度的一个独立单位。特点:线性,程的划分尺度小于进程,这使多线程程序拥有高并发进程在运行时各自内存单元相互独立,线程之间 内存共享,这使多线程编程可以拥有更好的性能和用户体验。
2、创建线程有几种方式 ?
- 继承 Thread 类并重写 run 方法创建线程,实现简单但不可以继承其他类
- 实现 Runnable 接口并重写 run 方法。避免了单继承局限性,编程更加灵活,实现 解耦。
- 实现 Callable 接口并重写 call 方法,创建线程。可以获取线程执行结果的返回值, 并且可以抛出异常。
- 使用线程池创建(使用 java.util.concurrent.Executor 接口)
3、Runnable 和 Callable 的区别?
主要区别Runnable 接口 run 方法无返回值;Callable 接口 call 方法有返回值,支持泛型Runnable 接口 run 方法只能抛出运行时异常,且无法捕获处理;Callable 接口 call方法允许抛出异常,可以获取异常信息
4、如何启动一个新线程、调用 start 和 run 方法的区别?
线程对象调用 run 方法不开启线程。仅是对象调用方法。线程对象调用 start 开启线程,并让 jvm 调用 run 方法在开启的线程中执行调用 start 方法可以启动线程,并且使得线程进入就绪状态,而 run 方法只是 thread的一个普通方法,还是在主线程中执行。
5、线程有哪几种状态以及各种状态之间的转换?
(1)第一是 new-> 新建状态。在生成线程对象, 并没有调用该对象的 start 方法,这是线程处于创建状态。(2)第二是 Runnable-> 就绪状态。当 调用了线程对象的 start 方法之后,该线程就进入了就绪状态,但是此时线程调度程序还没有把该线程设置为当前线程,此时处于就绪状态。(3)第三是 Running-> 运行状态。线程调度程序将处于就绪状态的线程 设置为当前线程,此时线程就进入了运行状态, 开始运行 run 函数当中的代码。(4)第四是 阻塞状态。阻塞状态是线程因为某种原因放弃 CPU 使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种:
- 等待 – 通过调用线程的 wait() 方法,让线程等待某工作的完成。
- 超时等待 – 通过调用线程的 sleep() 或 join()或发出了 I/O 请求时,线程会进 入到阻塞状态。当 sleep()状态超时、join()等待线程终止或者超时、或者 I/O 处理完毕时, 线程重新转入就绪状态。
- 同步阻塞 – 线程在获取 synchronized 同步锁失败(因为锁被其它线程所占用), 它会进入同步阻塞状态。
(5)第五是 dead-> 死亡状态: 线程执行完了或者因异常退出了 run()方法,该线程结束生命周期.
6、线程相关的基本方法?
- 线程等待(wait)
调用该方法的线程进入 WAITING 状态,只有等待另外线程的通知或被中断才会返回, 需要注意的是调用 wait()方法后,会释放对象的锁。因此,wait 方法一般用在同步方法或 同步代码块中。
- 线程睡眠(sleep)
sleep 导致当前线程休眠,与 wait 方法不同的是 sleep 不会释放当前占有的 锁,sleep(long)会导致线程进入 TIMED-WATING 状态,而 wait()方法会导致当前线程进 入 WATING 状态.
- 线程让步(yield)
yield 会使当前线程让出 CPU 执行时间片,与其他线程一起重新竞争 CPU 时间片。 一般情况下,优先级高的线程有更大的可能性成功竞争得到 CPU 时间片,但这又不是绝对 的,有的操作系统对 线程优先级并不敏感。
- 线程中断(interrupt)
中断一个线程,其本意是给这个线程一个通知信号,会影响这个线程内部的一个中断标 识位。这个线程本身并不会因此而改变状态(如阻塞,终止等)
- Join 等待其他线程终止
join() 方法,等待其他线程终止,在当前线程中调用一个线程的 join() 方法,则当前 线程转为阻塞状态,回到另一个线程结束,当前线程再由阻塞状态变为就绪状态,等待 cpu 的宠幸.
- 线程唤醒(notify)
Object 类中的 notify() 方法,唤醒在此对象监视器上等待的单个线程,如果所有线 程都在此对象上等待,则会选择唤醒其中一个线程,选择是任意的,并在对实现做出决定 时发生,线程通过调用其中一个 wait() 方法,在对象的监视器上等待,直到当前的线程放 弃此对象上的锁定,才能继续执行被唤醒的线程,被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争。类似的方法还有 notifyAll() ,唤醒再次监视器上等 待的所有线程。
7、 wait()和 sleep()的区别?
(1)来自不同的类wait():来自 Object 类;sleep():来自 Thread 类;(2)关于锁的释放:wait():在等待的过程中会释放锁;sleep():在等待的过程中不会释放锁(3)使用的范围:wait():必须在同步代码块中使用;sleep():可以在任何地方使用;(4)是否需要捕获异常wait():不需要捕获异常;sleep():需要捕获异常;
二、线程池
1、为什么需要线程池
在实际使用中,线程是很占用系统资源的,如果对线程管理不完善的话很容易导致系统问题。因此,在大多数并发框架中都会使用线程池来管理线程,使用线程池管理线程主要有如下好处:(1)使用线程池可以重复利用已有的线程继续执行任务,避免线程在创建销毁时造成的消耗(2)由于没有线程创建和销毁时的消耗,可以提高系统响应速度(3)通过线程可以对线程进行合理的管理,根据系统的承受能力调整可运行线程数量的大小等
2、线程池的分类(高薪常问)
(1)newCachedThreadPool:创建一个可进行缓存重复利用的线程池(2)newFixedThreadPool:创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程,线程池中的线程处于一定的量,可以很好的控制线程的并发量(3)newSingleThreadExecutor:创建一个使用单个 worker 线程的 Executor ,以无界队列方式来运行该线程。线程池中最多执行一个线程,之后提交的线程将会排在队列中以此执行(4)newSingleThreadScheduledExecutor:创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期执行(5)newScheduledThreadPool:创建一个线程池,它可安排在给定延迟后运行命令或者定期的执行(6)newWorkStealingPool:创建一个带并行级别的线程池,并行级别决定了同一时刻
最多有多少个线程在执行,如不传并行级别参数,将默认为当前系统的 CPU 个数
3、核心参数(高薪常问)
corePoolSize:核心线程池的大小maximumPoolSize:线程池能创建线程的最大个数keepAliveTime:空闲线程存活时间unit:时间单位,为 keepAliveTime 指定时间单位workQueue:阻塞队列,用于保存任务的阻塞队列threadFactory:创建线程的工程类handler:饱和策略(拒绝策略)
4、线程池的原理(高薪常问)
线程池的工作过程如下:当一个任务提交至线程池之后,(1)线程池首先判断核心线程池里的线程是否已经满了。如果不是,则创建一个新的工作线程来执行任务。否则进入(2)判断工作队列是否已经满了,倘若还没有满,将线程放入工作队列。否则进入 3.(3)判断线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行。如果线程池满了,则交给饱和策略来处理任务。
5、拒绝策略
ThreadPoolExecutor.AbortPolicy(系统默认):丢弃任务并抛出RejectedExecutionException 异常,让你感知到任务被拒绝了,我们可以根据业务逻辑选 择重试或者放弃提交等策略。ThreadPoolExecutor.DiscardPolicy: 也是丢弃任务,但是不抛出异常,相对而言存在一定的风险,因为我们提交的时候根本不知道这个任务会被丢弃,可能造成数据丢失。ThreadPoolExecutor.DiscardOldestPolicy: 丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程),通常是存活时间最长的任务,它也存在一定的数据丢失风险。ThreadPoolExecutor.CallerRunsPolicy:既不抛弃任务也不抛出异常,而是将某些任务回退到调用者,让调用者去执行它。
6、如何关闭线程池
关闭线程池,可以通过 shutdown 和 shutdownNow 两个方法原理:遍历线程池中的所有线程,然后依次中断1、shutdownNow 首先将线程池的状态设置为 STOP,然后尝试停止所有的正在执行和未执行任务的线程,并返回等待执行任务的列表;2、shutdown 只是将线程池的状态设置为 SHUTDOWN 状态,然后中断所有没有正在执行任务的线程
7、线程池中阻塞队列的作用?为什么是先添加列队而不是先创建最
大线程?
(1)一般的队列只能保证作为一个有限长度的缓冲区,如果超出了缓冲长度,就无法保留当前的任务了,阻塞队列通过阻塞可以保留住当前想要继续入队的任务。阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程,使得线程进入 wait 状态,释放 cpu 资源。阻塞队列自带阻塞和唤醒的功能,不需要额外处理,无任务执行时,线程池利用阻塞队列的 take 方法挂起,从而维持核心线程的存活、不至于一直占用 cpu 资源
(2)在创建新线程的时候,是要获取全局锁的,这个时候其它的就得阻塞,影响了整体效率。 就好比一个企业里面有 10 个(core)正式工的名额,最多招 10 个正式工,要是任务超过 正式工人数(task > core)的情况下,工厂领导(线程池)不是首先扩招工人,还是这 10人,但是任务可以稍微积压一下,即先放到队列去(代价低)。10 个正式工慢慢干,迟早会干完的,要是任务还在继续增加,超过正式工的加班忍耐极限了(队列满了),就的招外包帮忙了(注意是临时工)要是正式工加上外包还是不能完成任务,那新来的任务就会被领导拒绝了(线程池的拒绝策略)。
8、线程池中线程复用原理
线程池将线程和任务进行解耦,线程是线程,任务是任务,摆脱了之前通过 Thread 创建线程时的一个线程必须对应一个任务的限制。在线程池中,同一个线程可以从阻塞队列中不断获取新任务来执行,其核心原理在于线程池对 Thread 进行了封装,并不是每次执行任务都会调用 Thread.start() 来创建新线程,而是让每个线程去执行一个“循环任务”,在这个“循环任务”中不停检查是否有任务需要被执行,如果有则直接执行,也就是调用任务中的 run 方法,将 run 方法当成一个普通的方法执行,通过这种方式只使用固定的线程就将所有任务的 run 方法串联起来。
相关文章:

面试(03)————多线程和线程池
一、多线程 1、什么是线程?线程和进程的区别? 2、创建线程有几种方式 ? 3、Runnable 和 Callable 的区别? 4、如何启动一个新线程、调用 start 和 run 方法的区别? 5、线程有哪几种状态以及各种状态之间的转换? 6、线程…...

纯CSS实现未读消息显示99+
在大佬那看到这个小技巧,我觉得这个功能点还挺常用,所以给大家分享下具体的实现。当未读消息数小于100的时候显示准确数值,大于99的时候显示99。 1. 实现效果 2. 组件封装 <template><span class"col"><sup :styl…...
【C++】C++ primer plus 第十二章--类和动态内存分配
动态内存和类 关于静态数据成员 类之作声明,不分配内存,因此静态成员变量在类中不能进行初始化,需要在类外进行。特殊情况: 存在可以在类中声明静态成员并初始化的情况,成员类型为const整型或者const枚举类型。 特殊…...

分类预测 | Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机数据分类预测
分类预测 | Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机数据分类预测 目录 分类预测 | Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机数据分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机数据…...
使用PHP进行极验验证码动态参数提取与逆向分析
在网络安全领域,逆向工程和验证码破解是常见的技术挑战之一。极验验证码作为一种常见的人机验证工具,其动态参数的提取和逆向分析对于验证码的破解至关重要。本文将介绍如何使用PHP语言进行极验验证码动态参数的提取与逆向分析。 1. 准备工作 在开始之前…...

43.1k star, 免费开源的 markdown 编辑器 MarkText
43.1k star, 免费开源的 markdown 编辑器 MarkText 分类 开源分享 项目名: MarkText -- 简单而优雅的开源 Markdown 编辑器 Github 开源地址: https://github.com/marktext/marktext 官网地址: MarkText 支持平台: Linux, macOS 以及 Win…...

ArcGIS Pro怎么进行挖填方计算
在工程实施之前,我们需要充分利用地形,结合实际因素,通过挖填方计算项目的标高,以达到合理控制成本的目的,这里为大家介绍一下ArcGIS Pro中挖填方计算的方法,希望能对你有所帮助。 数据来源 教程所使用的…...

POLY - Survival Melee Weapons
一个轻便、有趣且灵活的低多边形资源包,非常适合原型设计或添加到低多边形世界中。超过50种近战武器、刀、斧、棍棒、棍棒等。 此套餐非常适合第三人称或自上而下的观看。 除此之外,资产还包括开发生存游戏可能需要的任何细节。 整个包是以多边形风格创建的,可以与其他多边…...

【ARMv7-M】| 01——阅读笔记 | 简介|应用程序级编程和内存模型
系列文章目录 【ARMv7-M】| 01——阅读笔记 | 简介|应用程序级编程和内存模型 失败了也挺可爱,成功了就超帅。 文章目录 前言1、简介2、应用程序级编程模型2.1 编程模式和访问等级2.2 数据类型和运算操作2.3 寄存器和执行状态1.2.4 异常和中断1.2.5 浮点单元寄存器…...

用Python做一个4399游戏脚本原来这么简单 !(内含完整思路)
说明 简述:本文将以4399小游戏《宠物连连看经典版2》作为测试案例,通过识别小图标,模拟鼠标点击,快速完成配对。对于有兴趣学习游戏脚本的同学有一定的帮助。 运行环境:Win10/Python3.5。 主要模块:win3…...

【计算机网络】应用层——HTTPS协议详解
文章目录 1. HTTPS 协议简介2. 了解“加密”3. HTTPS 保证数据安全传输的三大机制3.1 引入对称加密3.2 引入非对称加密3.3 引入“SSL/TLS证书”(防止中间人攻击)3.4 HTTPS安全机制总结 📄前言: 前面的文章已经对 HTTP 协议 进行了…...

私家侦探如何追踪难以找到的人?
私家侦探如何追踪难以找到的人? 私家侦探经常受雇于无从下手的情况,要在稀缺的信息中寻找蛛丝马迹,追踪那些难以捉摸的目标。在众多情境中,私家侦探或许能挖掘出丰富的信息。然而,若目标人物决心隐匿行踪,逃…...
一文讲透亚马逊云命令行使用
从配置开始 学习使用亚马逊云,自然免不了使用命令行工具,首先我们从下载和配置开始: 现在都使用V2版本的命令行工具,可以从官网下载最新的二进制安装包。1 首先是配置凭证: aws configure 输入之后会提示输入AK/SK…...

感染了后缀为.jayy勒索病毒如何应对?数据能够恢复吗?
导言: 在当今数字化的世界中,网络安全已经成为了每个人都需要关注的重要议题。而勒索病毒作为网络安全领域中的一大威胁,不断地演变和升级,给个人和组织带来了严重的损失和困扰。近期,一种名为.jayy的勒索病毒引起了广…...

一键快速彻底卸载:Mac软件轻松删除,瞬间释放磁盘空间
在接手使用前任员工遗留的Mac电脑时,经常面临的一个问题是内置了大量的非必要软件,这些软件不仅侵占了硬盘资源,还可能影响电脑整体性能。因此,迅速有效地删除这些冗余软件,以达成设备清爽、高效的初始化状态极其重要。…...

(React Hooks)前端八股文修炼Day9
一 对 React Hook 的理解,它的实现原理是什么 React Hooks是React 16.8版本中引入的一个特性,它允许你在不编写类组件的情况下,使用state以及其他的React特性。Hooks的出现主要是为了解决类组件的一些问题,如复杂组件难以理解、难…...
工厂方法模式:灵活的创建对象实例
在软件开发中,我们经常需要创建对象,但直接new一个实例可能会导致代码的耦合性增加,降低了代码的灵活性和可维护性。工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它提供了一种创建对象的接口…...
vue-codeirror编辑器vue3中的使用
vue-codeirror编辑器vue3中的使用 <script lang"ts" setup> import { ref,reactive } from vue; import { Codemirror } from "vue-codemirror"; import { oneDark } from "codemirror/theme-one-dark"; import { json } from codemirror/…...

搭建python编译环境
目录 1.安装依赖包 2.安装失败进行换源 3. 更新系统 通过C 语言调用 Python 代码,需要先安装 libpython3 的 dev 依赖库(不同的 ubuntu 版本下, python 版本 可能会有差异, 比如ubuntu 22.04 里是 libpython3.10-dev )…...
微信小程序登录流程
文章目录 1. 用户触发登录操作2. 获取临时登录凭证3. 发送登录凭证到服务器4. 后端使用 code 获取 session_key 和 openid5. 后端保存 session_key 和 openid 返回token6. 前端保存登录态 1. 用户触发登录操作 用户在小程序内部点击登录按钮或进行需要登录权限的操作ÿ…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
第25节 Node.js 断言测试
Node.js的assert模块主要用于编写程序的单元测试时使用,通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试,通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...