45 - 多线程性能优化常见问题

1、使用系统命令查看上下文切换

上下文切换常见的监测工具

1.1、Linux 命令行工具之 vmstat 命令

vmstat 是一款指定采样周期和次数的功能性监测工具,我们可以使用它监控进程上下文切换的情况。

img

vmstat 1 3 命令行代表每秒收集一次性能指标,总共获取 3 次。以下为上图中各个性能指标的注释:

  • procs r:等待运行的进程数 b:处于非中断睡眠状态的进程数
  • memory swpd:虚拟内存使用情况 free:空闲的内存 buff:用来作为缓冲的内存数 cache:缓存大小
  • swap si:从磁盘交换到内存的交换页数量 so:从内存交换到磁盘的交换页数量
  • io bi:发送到快设备的块数 bo:从块设备接收到的块数
  • system in:每秒中断数 cs:每秒上下文切换次数
  • cpu us:用户 CPU 使用事件 sy:内核 CPU 系统使用时间 id:空闲时间 wa:等待 I/O 时间 st:运行虚拟机窃取的时间

1.2、Linux 命令行工具之 pidstat 命令

我们通过上述的 vmstat 命令只能观察到哪个进程的上下文切换出现了异常,那如果是要查看哪个线程的上下文出现了异常呢?

pidstat 命令就可以帮助我们监测到具体线程的上下文切换。pidstat 是 Sysstat 中一个组件,也是一款功能强大的性能监测工具。我们可以通过命令 yum install sysstat 安装该监控组件。

通过 pidstat -help 命令,我们可以查看到有以下几个常用参数可以监测线程的性能:

img

常用参数:

  • -u:默认参数,显示各个进程的 cpu 使用情况;
  • -r:显示各个进程的内存使用情况;
  • -d:显示各个进程的 I/O 使用情况;
  • -w:显示每个进程的上下文切换情况;
  • -p:指定进程号;
  • -t:显示进程中线程的统计信息

首先,通过 pidstat -w -p pid 命令行,我们可以查看到进程的上下文切换:

img

  • cswch/s:每秒主动任务上下文切换数量
  • nvcswch/s:每秒被动任务上下文切换数量

之后,通过 pidstat -w -p pid -t 命令行,我们可以查看到具体线程的上下文切换:

img

1.3、JDK 工具之 jstack 命令

查看具体线程的上下文切换异常,我们还可以使用 jstack 命令查看线程堆栈的运行情况。jstack 是 JDK 自带的线程堆栈分析工具,使用该命令可以查看或导出 Java 应用程序中的线程堆栈信息。

jstack 最常用的功能就是使用 jstack pid 命令查看线程堆栈信息,通常是结合 pidstat -p pid -t 一起查看具体线程的状态,也经常用来排查一些死锁的异常。

img

每个线程堆栈的信息中,都可以查看到线程 ID、线程状态(wait、sleep、running 等状态)以及是否持有锁等。

我们可以通过 jstack 16079 > /usr/dump 将线程堆栈信息日志 dump 下来,之后打开 dump 文件,通过查看线程的状态变化,就可以找出导致上下文切换异常的具体原因。例如,系统出现了大量处于 BLOCKED 状态的线程,我们就需要立刻分析代码找出原因。

2、多线程队列

在 Java 多线程应用中,特别是在线程池中,队列的使用率非常高。Java 提供的线程安全队列又分为了阻塞队列和非阻塞队列。

2.1、阻塞队列

我们先来看下阻塞队列。阻塞队列可以很好地支持生产者和消费者模式的相互等待,当队列为空的时候,消费线程会阻塞等待队列不为空;当队列满了的时候,生产线程会阻塞直到队列不满。

在 Java 线程池中,也用到了阻塞队列。当创建的线程数量超过核心线程数时,新建的任务将会被放到阻塞队列中。我们可以根据自己的业务需求来选择使用哪一种阻塞队列,阻塞队列通常包括以下几种:

  • ArrayBlockingQueue:一个基于数组结构实现的有界阻塞队列,按 FIFO(先进先出)原则对元素进行排序,使用 ReentrantLock、Condition 来实现线程安全;
  • LinkedBlockingQueue:一个基于链表结构实现的阻塞队列,同样按 FIFO (先进先出) 原则对元素进行排序,使用 ReentrantLock、Condition 来实现线程安全,吞吐量通常要高于 ArrayBlockingQueue;
  • PriorityBlockingQueue:一个具有优先级的无限阻塞队列,基于二叉堆结构实现的无界限(最大值 Integer.MAX_VALUE - 8)阻塞队列,队列没有实现排序,但每当有数据变更时,都会将最小或最大的数据放在堆最上面的节点上,该队列也是使用了 ReentrantLock、Condition 实现的线程安全;
  • DelayQueue:一个支持延时获取元素的无界阻塞队列,基于 PriorityBlockingQueue 扩展实现,与其不同的是实现了 Delay 延时接口;
  • SynchronousQueue:一个不存储多个元素的阻塞队列,每次进行放入数据时, 必须等待相应的消费者取走数据后,才可以再次放入数据,该队列使用了两种模式来管理元素,一种是使用先进先出的队列,一种是使用后进先出的栈,使用哪种模式可以通过构造函数来指定。

Java 线程池 Executors 还实现了以下四种类型的 ThreadPoolExecutor,分别对应以上队列,详情如下:

img

2.2、非阻塞队列

我们常用的线程安全的非阻塞队列是 ConcurrentLinkedQueue,它是一种无界线程安全队列 (FIFO),基于链表结构实现,利用 CAS 乐观锁来保证线程安全。

下面我们通过源码来分析下该队列的构造、入列以及出列的具体实现。

构造函数:ConcurrentLinkedQueue 由 head 、tair 节点组成,每个节点(Node)由节点元素(item)和指向下一个节点的引用 (next) 组成,节点与节点之间通过 next 关联,从而组成一张链表结构的队列。在队列初始化时, head 节点存储的元素为空,tair 节点等于 head 节点。

public ConcurrentLinkedQueue() {head = tail = new Node<E>(null);
}private static class Node<E> {volatile E item;volatile Node<E> next;..
}

入列:当一个线程入列一个数据时,会将该数据封装成一个 Node 节点,并先获取到队列的队尾节点,当确定此时队尾节点的 next 值为 null 之后,再通过 CAS 将新队尾节点的 next 值设为新节点。此时 p != t,也就是设置 next 值成功,然后再通过 CAS 将队尾节点设置为当前节点即可。

public boolean offer(E e) {checkNotNull(e);// 创建入队节点final Node<E> newNode = new Node<E>(e);//t,p 为尾节点,默认相等,采用失败即重试的方式,直到入队成功         for (Node<E> t = tail, p = t;;) {// 获取队尾节点的下一个节点Node<E> q = p.next;// 如果 q 为 null,则代表 p 就是队尾节点if (q == null) {// 将入列节点设置为当前队尾节点的 next 节点if (p.casNext(null, newNode)) {// 判断 tail 节点和 p 节点距离达到两个节点if (p != t) // hop two nodes at a time// 如果 tail 不是尾节点则将入队节点设置为 tail。// 如果失败了,那么说明有其他线程已经把 tail 移动过 casTail(t, newNode);  // Failure is OK.return true;}}// 如果 p 节点等于 p 的 next 节点,则说明 p 节点和 q 节点都为空,表示队列刚初始化,所以返回  else if (p == q)p = (t != (t = tail)) ? t : head;else// Check for tail updates after two hops.p = (p != t && t != (t = tail)) ? t : q;}}

出列:首先获取 head 节点,并判断 item 是否为 null,如果为空,则表示已经有一个线程刚刚进行了出列操作,然后更新 head 节点;如果不为空,则使用 CAS 操作将 head 节点设置为 null,CAS 就会成功地直接返回节点元素,否则还是更新 head 节点。

    public E poll() {// 设置起始点restartFromHead:for (;;) {//p 获取 head 节点for (Node<E> h = head, p = h, q;;) {// 获取头节点元素E item = p.item;// 如果头节点元素不为 null,通过 cas 设置 p 节点引用的元素为 nullif (item != null && p.casItem(item, null)) {// Successful CAS is the linearization point// for item to be removed from this queue.if (p != h) // hop two nodes at a timeupdateHead(h, ((q = p.next) != null) ? q : p);return item;}// 如果 p 节点的下一个节点为 null,则说明这个队列为空,更新 head 结点else if ((q = p.next) == null) {updateHead(h, p);return null;}// 节点出队失败,重新跳到 restartFromHead 来进行出队else if (p == q)continue restartFromHead;elsep = q;}}}

ConcurrentLinkedQueue 是基于 CAS 乐观锁实现的,在并发时的性能要好于其它阻塞队列,因此很适合作为高并发场景下的排队队列。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/194956.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【JavaSE】:String(二):深入String

深入String 一.字符串的存储二.字符串的不可变性三.字符串修改四.StringBuilder和StringBuffer 一.字符串的存储 我们知道双引号里的数据都是字符串常量&#xff0c;储存在字符串常量池当中。 例子 直接使用是比较地址。字符串常量池有一个特点&#xff1b;它会先检查该常量是否…

LLM-Intro to Large Language Models

LLM some LLM’s model and weight are not opened to user what is? Llama 270b model 2 files parameters file parameter or weight of neural networkparameter – 2bytes, float number code run parameters(inference) c or python, etcfor c, 500 lines code withou…

中介者模式 rust和java的实现

文章目录 中介者模式介绍实现javarustrust仓库 中介者模式 中介者模式&#xff08;Mediator Pattern&#xff09;又被称为 调停者模式 。 它定义了一个中介对象来封装一系列对象之间的交互关系。 中介者使各个对象之间不需要显式地相互引用&#xff0c;从而使耦合性降低&#…

计算机网络扫盲(4)——时延

一、概述 在这里&#xff0c;我们考虑分组交换网的情况&#xff0c;因特网可以被看成是一种基础设施&#xff0c;该基础设施为运行在端系统上的分布式应用提供服务。在理想情况下&#xff0c;我们希望因特网服务能够在任意两个端系统之间随心所欲地移动数据而没有任何数据地丢失…

韩语图片文字如何转为纯文本?

如何将上图为韩语的图片转为文本文件&#xff1f;这个需要用到OCR程序&#xff0c;操作方法如下&#xff1a; 一、打开金鸣识别网站。 二、点击“点击添加图片/PDF”&#xff0c;将待识别的图片添加到列表。 三、识别模块点选“通用文字”&#xff0c;输出格式选择“纯文本输出…

陀螺仪LSM6DSV16X与AI集成(1)----轮询获取陀螺仪数据

陀螺仪LSM6DSV16X与AI集成.1--轮询获取陀螺仪数据 概述视频教学样品申请通信模式管脚定义IIC通信模式速率生成STM32CUBEMX串口配置IIC配置CS和SA0设置串口重定向参考程序初始换管脚获取ID复位操作BDU设置设置量程和速率配置过滤链轮询读取数据主程序演示 概述 本文将介绍如何使…

PPT设置背景颜色

问题描述&#xff1a;PPT如何设置背景颜色&#xff1f; 问题解决&#xff1a;设计→设置背景格式→颜色→蓝色&#xff08;最好选择看着比较舒服的颜色&#xff09;

如何通过缺口发现短线机会?

一、认识缺口形态 新手一开始接触技术分析&#xff0c;可能都以为“缺口”是一个很高深的技术形态。其实缺口很简单&#xff0c;就是K线图中的价格空白区域&#xff0c;也就是股价上涨或下跌的过程中&#xff0c;跳过了这个价格。根据跳空的方向不同&#xff0c;缺口可以分为向…

AArch64中的虚拟化

运行在EL2或更高级别的软件具有对虚拟化的几个控制权限&#xff1a; • 第二阶段翻译&#xff08;Stage 2 translation&#xff09; • EL1/0指令和寄存器访问trapping • 虚拟异常生成 非安全状态和安全状态下的异常级别&#xff08;ELs&#xff09;如下图所示&#xff1a; 在…

SAP_ABAP_RZ11解决SAP运行超时问题 TIME_OUT / rdisp/scheduler/prio_high/max_runtime

SAP ABAP 顾问&#xff08;开发工程师&#xff09;能力模型_Terry谈企业数字化的博客-CSDN博客文章浏览阅读510次。目标&#xff1a;基于对SAP abap 顾问能力模型的梳理&#xff0c;给一年左右经验的abaper 快速成长为三年经验提供超级燃料&#xff01;https://blog.csdn.net/j…

音频处理关键知识点

1 引言 现实生活中&#xff0c;我们听到的声音都是时间连续的&#xff0c;我们称为这种信号叫模拟信号。模拟信号需要进行数字化以后才能在计算机中使用。 目前我们在计算机上进行音频播放都需要依赖于音频文件。音频文件的生成过程是将声音信息采样、量化和编码产生的数字信号…

linux无网络 无ip,显示网络未连接

标题:linux无网络 无ip&#xff0c;显示网络未连接 参考blog&#xff1a;Linux无网络连接问题排查 首先我们发现ens33没有ip地址&#xff0c;说明这个接口并没有被分到ip&#xff1b; 我们可以通过手动方式来给ens33获得网络ip sudo dhclient ens33&#xff0c;之后再输入ifc…

FPGA UltraScale GTH 全网最细讲解,aurora 8b/10b编解码,HDMI视频传输,提供2套工程源码和技术支持

目录 1、前言免责声明 2、我这里已有的 GT 高速接口解决方案3、详细设计方案设计框图视频源选择ADV7611解码芯片配置及采集动态彩条视频数据组包UltraScale GTH 全网最细解读UltraScale GTH 基本结构参考时钟的选择和分配UltraScale GTH 发送和接收处理流程UltraScale GTH 发送…

【小沐学Python】Python实现Web服务器(Flask+celery,生产者-消费者)

文章目录 1、简介2、安装和下载2.1 flask2.2 celery2.3 redis 3、功能开发3.1 创建异步任务的方法3.1.1 使用默认的参数3.1.2 指定相关参数3.1.3 自定义Task基类 3.2 调用异步任务的方法3.2.1 app.send_task3.2.2 Task.delay3.2.3 Task.apply_async 3.3 获取任务结果和状态 4、…

用CHAT如何写教研室工作总结?

问CHAT&#xff1a;写一份教研室工作总结 CHAT回复&#xff1a;以下是一个教研室工作总结的大纳&#xff0c;具体内容需要根据你们教研室的实际情况进行填充和修改。 教研室XXXX年度工作总结 1. 引言&#xff1a;简要介绍本年度工作总结的目的和主题。 2. 教育教学工作&…

Java核心知识点整理大全24-笔记

目录 22. 数据结构 22.1.1. 栈&#xff08;stack&#xff09; 22.1.2. 队列&#xff08;queue&#xff09; 22.1.3. 链表&#xff08;Link&#xff09; 22.1.4. 散列表&#xff08;Hash Table&#xff09; 22.1.5. 排序二叉树 22.1.5.1. 插入操作 22.1.5.2. 删除操作 2…

知识点滴 - 什么是半透膜和渗透压

半透膜和渗透作用 1748年的一天&#xff0c;法国物理学家诺勒为了改进酒的制作水平&#xff0c;设计了这样一个试验&#xff1a;在一个玻璃圆筒中装满酒精&#xff0c;用猪膀胱封住&#xff0c;然后把圆筒全部浸在水中。当他正要做下一步的工作时&#xff0c;突然发现&#xff…

DDOS攻击为何永不过时?

文章目录 一、DOS二、DDOS三、如何防范DDOS 1.可以过滤IP地址2.增加设备3.在骨干节点配置防火墙4.开启过滤5.配置DNS抗攻击6.白帽团队 四、白帽子 为什么二十年前中国红客们就在用的DDOS攻击直到现在还依然是黑客们最爱的攻击方法&#xff1f;二十年前的攻击技术为什么还不过…

基于Java SSM框架+Vue实现教学视频点播网站项目【项目源码+论文说明】计算机毕业设计

基于java的SSM框架Vue实现教学视频点播网站演示 摘要 随着现在网络的快速发展&#xff0c;网上管理系统也逐渐快速发展起来&#xff0c;网上管理模式很快融入到了许多学院的之中&#xff0c;随之就产生了“视频点播系统”&#xff0c;这样就让视频点播系统更加方便简单。 对于…

Java 学习之多态

多态的概念 多态 晚绑定。 所谓多态&#xff0c;就是父类型的引用可以指向子类型的对象&#xff0c;或者接口类型的引用可以指向实现该接口的类的实例。 不要把函数重载理解为多态。因为多态是一种运行期的行为&#xff0c;不是编译期的行为。 多态&#xff1a;父类型的引用可…