java多线程中常用指令
------------恢复内容开始------------
一、写在前面
好久没写博客了,这不快毕业了,应该会重新开始更新博客了。这次主要介绍查看线程状态等一系列常见指令,包括有jps、vmstat、jstack、javap、以及如何查看java对应的汇编代码。
二、情景
依据假设情景来说明为啥以及如何使用这些指令。现在你是个初出茅庐的java程序员,你一看现在的业务用的单线程处理,大吃一斤,马上提出我要优化,改成多线程,然后写下了如下代码。然后你把代码提交,上线,准备感受多线程的速度。然而业务上线后直接瘫痪,这时你该怎么办。
package com.wx.ch1;
public class DeadLockDemo {
private static String A = "A";
private static String B = "B";
public static void main(String[] args){
new DeadLockDemo().DeadLock();
}
private void DeadLock(){
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (A){
try {
Thread.currentThread().sleep(2000);
}catch (InterruptedException e){
e.printStackTrace();
}
synchronized (B){
System.out.println("get A B");
}
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (B){
synchronized (A){
System.out.println("get B A");
}
}
}
});
t1.start();
t2.start();
}
}
三、发现问题
首先,你希望你能够获得现在这些线程所处状态,然后判断发生了什么,jstack指令可以帮到你。
3.1 jstack指令
该指令常被用于dump出指定进程下,所有线程的信息。指令格式如下:
sudo -u 用户名 jstack指令位置 进程id >文件名
其中jstack指令位置由你安装java的位置决定,你可以通过echo $JAVA_HOME、whereis java等命令进行查询。文件名表示输出重定向的结果,可以把结果存入对应的文件方便查看。
我使用的指令样例:
sudo -u wx /home/wx/java/jdk1.8/bin/jstack 32763 >/home/wx/result
我们先来看看结果,结果很明显表明两个线程都被阻塞了,互相等待对方释放锁。

3.2 jps指令
如果你按照jstack的指令尝试打印出线程信息,你会发现缺少指令中的进程id。那么该如何查询这些运行中的java进程id?常见的查询进程id指令是ps,java为我们提供了
专门的查询运行在jvm上的java进程id指令,即jps指令。
指令格式:jps

3.3 vmstat
现在你通过上面两个指令的组合发现了死锁的问题,你改写了代码,成功运行在服务器上了,下一步你要做的是精益求精,开始优化!当然优化是件很复杂的事情,这边只提通过查看切换上下文次数的指令vmstat来判断当前多线程代码运行情况。
指令格式:vmstat (后面可以接参数 可自行vmstat -h 查看)
最常见的为 vmstat -t 1 (每间隔一秒时间打印一次)
vmstat -t 1

图中cs(Content Swich)列为即为上下文切换次数。
3.4 javap & java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
这两个指令被用于查看对应的java字节码以及汇编代码。在本文的场景中,我们通过javap以及虚拟机启动命令行参数,查看并验证volatile关键字的底层实现。
在多个材料中均提及带有volatuke关键字的变量在修改时,对应生成的汇编代码带有lock前缀,我们要做的就是验证这一点。
验证代码:
package com.wx.ch1;
public class RecordExample {
int a =0;
volatile boolean flag = false;
public void writer(){
flag = true;
for(int i=0;i<1000000;i++){
}
a = 1;
}
public boolean reader(){
if(flag){
int i = a*a;
System.out.println(i);
return true;
}
return false;
}
public static void main(String[] args) {
RecordExample re = new RecordExample();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
re.writer();
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
for (;;){
if (re.reader()){
break;
}
}
}
});
t1.start();
t2.start();
}
}
代码的逻辑无需在意,只需要关注该代码对于volatile声明的变量flag进行了修改。
通过指令:javap -v RecordExample(视具体路径需要补充包名)
得到关键字节码如下,可以看到flags变量声明带有ACC_VOLATILE标识,该标识对应于jvm中的源码方法,该方法负责生成适配不同机器的操作系统,转换成同等语义的汇编代码,即在该代码中,该字节码对应的
汇编代码,被插入了lock前缀的指令。

通过虚拟机指令查看进一步查看字节码对应的汇编代码
java -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly 类名
在实际使用该指令查看汇编代码的过程中,遇到了不少问题。
1)获得的汇编代码为16进制格式,无法理解代码含义。经过判断认为是jdk版本的原因导致,之前所使用的版本为open-jdk17,在替换成oracle-jdk1.8以后,可以见到明文形式的汇编代码。
2)在更换完版本以后运行该指令发现缺少对应的组件hsdis-amd64.so。如果没有下载并添加该组件,运行指令时会显示can not load hsdis-amd64.so。该组件是ubuntu下的格式,windows下的版本不同。windows版本网络上
很多,直接搜索hsdis dll关键字。这里提供一下linux上64位的该组件下载地址:链接: https://pan.baidu.com/s/1FkDyXDhoPk3XLfsNx3U3Rw 提取码: 1ta3 复制这段内容后打开百度网盘手机App,操作更方便哦。
3)完成下载以后,在linux操作系统中需要将该文件粘贴复制到java安装目录下的/jre/lib/amd64,我的粘贴路径为:/home/wx/java/jdk1.8/jre/lib/amd64。同意可以通过echo $JAVA_HOME查询jdk安装目录,前提是配置了环境变量。
在完成上述一系列操作以后,就可以在控制台敲上述指令观察得到对应的汇编代码。在这里我们通过开发工具idea完成相关虚拟机指令配置,直接在idea中输出对应的汇编代码。
对应配置截图如下

如果没有虚拟机的配置项,则点击modify options增加vm配置 ,勾选add VM options:

生成汇编代码截图:可以看到对应指令带有的lock前缀,注解部分显示是操作volatile变量。

接着我们将代码flag变量声明的volatile删除,声明为一般变量,再次查看对应的汇编代码,会发现不再有带有lock前缀的对于变量值修改的指令。
四、最后
总结一下,介绍了与多线程编程相关的一些基础指令,首先通过jps配合jstack可以查看当前线程的状态信息;接着,可以通过vmstat指令去查看线程的导致的上下文切换次数,该指标是反应多线程性能的一个重要指标,过多的上下文切换会影响线程的执行速度。最后,介绍了查看java对应字节码与汇编代码的指令。
------------恢复内容结束------------
java多线程中常用指令的更多相关文章
- java多线程中的三种特性
java多线程中的三种特性 原子性(Atomicity) 原子性是指在一个操作中就是cpu不可以在中途暂停然后再调度,既不被中断操作,要不执行完成,要不就不执行. 如果一个操作时原子性的,那么多线程并 ...
- JAVA项目中常用的异常处理情况总结
JAVA项目中常用的异常知识点总结 1. java.lang.nullpointerexception这个异常大家肯定都经常遇到,异常的解释是"程序遇上了空指针",简单地说就是调用 ...
- JAVA项目中常用的异常知识点总结
JAVA项目中常用的异常知识点总结 1. java.lang.nullpointerexception这个异常大家肯定都经常遇到,异常的解释是"程序遇上了空指针",简单地说就是调用 ...
- java 多线程中的wait方法的详解
java多线程中的实现方式存在两种: 方式一:使用继承方式 例如: PersonTest extends Thread{ String name; public PersonTest(String n ...
- java多线程中并发集合和同步集合有哪些?区别是什么?
java多线程中并发集合和同步集合有哪些? hashmap 是非同步的,故在多线程中是线程不安全的,不过也可以使用 同步类来进行包装: 包装类Collections.synchronizedMap() ...
- java多线程中最佳的实践方案是什么?
java多线程中最佳的实践方案是什么? 给你的线程起个有意义的名字.这样可以方便找bug或追踪.OrderProcessor, QuoteProcessor or TradeProcessor 这种名 ...
- Java多线程中的常用方法
本文将带你讲诉Java多线程中的常用方法 Java多线程中的常用方法有如下几个 start,run,sleep,wait,notify,notifyAll,join,isAlive,current ...
- Java多线程中的竞争条件、锁以及同步的概念
竞争条件 1.竞争条件: 在java多线程中,当两个或以上的线程对同一个数据进行操作的时候,可能会产生“竞争条件”的现象.这种现象产生的根本原因是因为多个线程在对同一个数据进行操作,此时对该数据的操作 ...
- Java开发中常用jar包整理及使用
本文整理了我自己在Java开发中常用的jar包以及常用的API记录. <!-- https://mvnrepository.com/artifact/org.apache.commons/com ...
随机推荐
- Android Studio中添加对HttpClient的支持包
感谢大佬:https://blog.csdn.net/gladiator0975/article/details/49177959 sdk6.0以后取消了HttpClient,设置android SD ...
- 在Spring Boot中从类路径加载文件
介绍 创建Spring Boot Web应用程序时,有时有时需要从类路径中加载文件:war和jar的加载文件格式是不一样的 在下面,您将找到在WAR和JAR中加载文件的解决方案. 资源加载器 使用Ja ...
- Android 如何让EditText不自动获取焦点&隐藏软键盘
感谢大佬:https://blog.csdn.net/a18615971648/article/details/72869345 有时候的项目当中进入某个页面edittext会自动获取焦点弹出软键盘, ...
- EasyExcel小试牛刀
原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/12029411.html 某种偶然的机会遇到了这个插件, 听说很牛X, 我之前也不知道, 不过还 ...
- iOS App 架构文章推荐
iOS应用开发架构 iOS应用架构谈系列 阿里技术沙龙 2.2.1. Hybrid App 2.2.2. taobao 客户端架构 2.2.3. alipay 客户端架构 iOS APP 架构漫谈 ...
- 添加了tabBar之后就不能使用wx.navigateTo跳转页面
我在app.json中添加了增加底部选项卡的代码如下: { "pages": [ "pages/index/index", "pages/lo ...
- WebGPU 中的缓冲映射机制
1. 什么是缓冲映射 就不给定义了,直接简单的说,映射(Mapping)后的某块显存,就能被 CPU 访问. 三大图形 API(D3D12.Vulkan.Metal)的 Buffer(指显存)映射后, ...
- 02网络编程( socket套接字+TCP粘包 )
目录 02 网络编程 一.socket套接字编程 二.简易代码模板 2.1 服务端 2.2 客户端 三.通信循环及代码优化 四.黏包现象 五.struct模块 六.简易版本报头 七.上传文件数据 * ...
- JTAG 标准IEEE STD 1149.1-2013学习笔记(一·)Test logic architecture、Instruction register以及Test data registers
我是 雪天鱼,一名FPGA爱好者,研究方向是FPGA架构探索和SOC设计. 关注公众号[集成电路设计教程],拉你进"IC设计交流群". 注:转载请注明出处 一.Test logic ...
- JAVA 1.对象和封装
1. 2. 3.Java类里面属性可以付初使值 4.属性的名字一小写开头 5 6.构造方法 1.语法: 7.staitc的应用 1.statia可以用来修饰:方法,属性,代码块 , st ...