线程基础知识06 synchronized---使用javap查看相关指令
1 示例-简单同步代码块
public class SychTest9 { public static void main(String[] args) {
Object o = new Object();
synchronized (o){
System.out.println("aaa");
}
}
}
使用javap查看指令(复制了部分)
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: new #2 // class java/lang/Object
3: dup
4: invokespecial #1 // Method java/lang/Object."<init>":()V
7: astore_1
8: aload_1
9: dup
10: astore_2
11: monitorenter
12: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #4 // String aaa
17: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: aload_2
21: monitorexit
22: goto 30
25: astore_3
26: aload_2
27: monitorexit
28: aload_3
29: athrow
30: return
可以看到下面三个指令,一个monitorenter 指令,两个monitorexit
11: monitorenter 进入管程 21: monitorexit 出管程 27: monitorexit 出管程
synchronized
同步语句块的实现使用的是 monitorenter
和 monitorexit
指令,其中 monitorenter
指令指向同步代码块的开始位置, monitorexit
指令则指明同步代码块的结束位置。**
当执行 monitorenter
指令时,线程试图获取锁也就是获取 对象监视器 monitor
的持有权
在 Java 虚拟机(HotSpot)中,Monitor 是基于 C++实现的,由ObjectMonitor实现的。每个对象中都内置了一个 ObjectMonitor
对象。
另外,wait/notify
等方法也依赖于monitor
对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify
等方法,否则会抛出java.lang.IllegalMonitorStateException
的异常的原因。
在执行monitorenter
时,会尝试获取对象的锁,如果锁的计数器为 0 则表示锁可以被获取,获取后将锁计数器设为 1 也就是加 1。
在执行 monitorexit
指令后,将锁计数器设为 0,表明锁被释放。如果获取对象锁失败,那当前线程就要阻塞等待,直到锁被另外一个线程释放为止
这里为什么有两个monitorexit指令呢?
第一个monitorexit指令是同步代码块正常释放锁的一个标志;
如果同步代码块中出现Exception或者Error,则会调用第二个monitorexit指令来保证释放锁
2 示例-简单同步代码块+异常
在同步代码块中手动抛出异常
public class SychTest10 { public static void main(String[] args) throws Exception {
Object o = new Object();
synchronized (o){
System.out.println("aaa");
throw new Exception();
}
}
}
使用javap查看指令(复制了部分)
/*
public static void main(java.lang.String[]) throws java.lang.Exception;
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: new #2 // class java/lang/Object
3: dup
4: invokespecial #1 // Method java/lang/Object."<init>":()V
7: astore_1
8: aload_1
9: dup
10: astore_2
11: monitorenter
12: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #4 // String aaa
17: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: new #6 // class java/lang/Exception
23: dup
24: invokespecial #7 // Method java/lang/Exception."<init>":()V
27: athrow
28: astore_3
29: aload_2
30: monitorexit
31: aload_3
32: athrow
*/
可以看到monitorenter和monitorexit,athrow和athrow,保证释放锁
11: monitorenter 27: athrow 30: monitorexit 32: athrow
3 示例-普通同步方法
public class SychTest11 { public synchronized void aa() {
System.out.println("aaa");
} public static void main(String[] args) { }
使用javap查看指令(复制了部分)
public synchronized void aa();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String aaa
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
可以看到,可以没有了monitorenter和monitorexit指令,但是有一个标识ACC_SYNCHRONIZED,标识它是一个同步方法
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
4 示例 静态同步方法
public class SychTest12 { public static synchronized void aa() {
System.out.println("aaa");
} public static void main(String[] args) {
aa();
}
}
使用javap查看指令(复制了部分)
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
Code:
stack=2, locals=0, args_size=0
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String aaa
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 6: 0
line 7: 8
可以看到,可以没有了monitorenter和monitorexit指令,但是有一个标识ACC_SYNCHRONIZED,标识它是一个同步方法,且ACC_STATIC标识是静态方法
flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
5 小结
synchronized
同步语句块的实现使用的是 monitorenter
和 monitorexit
指令,其中 monitorenter
指令指向同步代码块的开始位置,monitorexit
指令则指明同步代码块的结束位置。正常情况下回有两个monitorexit
指令,为了在出现异常也能够成功释放锁。
synchronized
修饰的方法并没有 monitorenter
指令和 monitorexit
指令,取得代之的确实是 ACC_SYNCHRONIZED
标识,该标识指明了该方法是一个同步方法。
不过两者的本质都是对监视器 monitor 的获取
线程基础知识06 synchronized---使用javap查看相关指令的更多相关文章
- Java并发编程(一):线程基础知识以及synchronized关键字
1.线程与多线程的概念:在一个程序中,能够独立运行的程序片段叫作“线程”(Thread).多线程(multithreading)是指从软件或者硬件上实现多个线程并发执行的技术. 2.多线程的意义:多线 ...
- java线程基础知识----线程与锁
我们上一章已经谈到java线程的基础知识,我们学习了Thread的基础知识,今天我们开始学习java线程和锁. 1. 首先我们应该了解一下Object类的一些性质以其方法,首先我们知道Object类的 ...
- java线程基础知识----线程基础知识
不知道从什么时候开始,学习知识变成了一个短期记忆的过程,总是容易忘记自己当初学懂的知识(fuck!),不知道是自己没有经常使用还是当初理解的不够深入.今天准备再对java的线程进行一下系统的学习,希望 ...
- Windows核心编程 第六章 线程基础知识 (上)
第6章 线程的基础知识 理解线程是非常关键的,因为每个进程至少需要一个线程.本章将更加详细地介绍线程的知识.尤其是要讲述进程与线程之间存在多大的差别,它们各自具有什么作用.还要介绍系统如何使用线程内核 ...
- Java__线程---基础知识全面实战---坦克大战系列为例
今天想将自己去年自己编写的坦克大战的代码与大家分享一下,主要面向学习过java但对java运用并不是很熟悉的同学,该编程代码基本上涉及了java基础知识的各个方面,大家可以通过练习该程序对自己的jav ...
- Java 线程基础知识
前言 什么是线程?线程,有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元.一个标准的线程由线程 ID,当前指令指针 (PC),寄存器集合和堆栈组成.另外,线 ...
- Windows核心编程 第六章 线程基础知识 (下)
6.6 线程的一些性质 到现在为止,讲述了如何实现线程函数和如何让系统创建线程以便执行该函数.本节将要介绍系统如何使这些操作获得成功. 图6 - 1显示了系统在创建线程和对线程进行初始化时必须做些什么 ...
- 基础知识系列☞Abstract和Virtual→及相关知识
转载地址→http://www.cnblogs.com/blsong/archive/2010/08/12/1798064.html 在C#的学习中,容易混淆virtual方法和abstract方法的 ...
- Java多线程系列 基础篇06 synchronized(同步锁)
转载 http://www.cnblogs.com/paddix/ 作者:liuxiaopeng http://www.infoq.com/cn/articles/java-se-16-synchro ...
- Java并发之线程管理(线程基础知识)
因为书中涵盖的知识点比较全,所以就以书中的目录来学习和记录.当然,学习书中知识的时候自己的思考和实践是最重要的.说到线程,脑子里大概知道是个什么东西,但很多东西都还是懵懵懂懂,这是最可怕的.所以想着细 ...
随机推荐
- 【题解】CF1503B 3-Coloring
题面传送门 解决思路 讲一下 \(\text{VP}\) 时的思路. 首先想到,只要能将棋盘中红色或蓝色部分全部填成同一个数,那么剩下的就不会受限了(可行有两个,限制只有一个): 但考虑到交互库可能有 ...
- K8s如何启用cgroup2支持?
什么是 cgroup ️Reference: control groups(控制组),通常被称为cgroup,是Linux内核的一项功能.它允许将进程组织成分层的组,然后限制和监控各种资源的使用. 内 ...
- 金山云:基于 JuiceFS 的 Elasticsearch 温冷热数据管理实践
01 Elasticsearch 广泛使用带来的成本问题 Elasticsearch(下文简称"ES")是一个分布式的搜索引擎,还可作为分布式数据库来使用,常用于日志处理.分析和搜 ...
- python面试题常用语句
一.比较与交换1.比较并输出大的 print(a if a>b else b) 2.交换两个元素 a,b = b,alist1[i],list[j]=list1[j],list[i] 二.排序 ...
- linux系统移植
1 linux环境搭建 1.1 添加交叉开发工具链 新建如下工程目录: gcc-4.6.4.tar.xz #拷贝 tar -Jxvf gcc-4.6.4.tar.xz #解压 cd ./gcc-4.6 ...
- JSON提取器中串联一个接口的多个值传给下个接口(compute concatenation var的实际使用场景)
实际场景:某功能在前端支持选择多条数据后点击提交,表现在接口是,一次传了多个Id. 问题:需要将上个接口的多个Id串联,传给提交接口. 处理方式:通过JSON提取器勾选:compute concate ...
- JavaEE Day14 Servlet&HTTP&Request
今日内容 1.Servlet 2.HTTP协议 3.Request 一.Servlet 1.概念 2.步骤 3.执行原理 4.生命周期 5.Servlet 3.0注解配置 6.Servlet体系结构 ...
- 【Shell案例】【while循环、正则表达式、sed、awk、grep】5、打印空行的行号
描述写一个 bash脚本以输出一个文本文件 nowcoder.txt中空行的行号,可能连续,从1开始 示例:假设 nowcoder.txt 内容如下:ab c d e f 你的脚本应当输出:35791 ...
- 【十次方微服务后台开发】Day02:加密与JWT鉴权、微服务注册中心、配置中心、熔断器、网关、消息总线、部署与持续集成、容器管理与监控Rancher、influxDB、grafana
一.密码加密与微服务鉴权JWT 1.BCrypt密码加密 Spring Security 提供了BCryptPasswordEncoder类,实现Spring的PasswordEncoder接口使用B ...
- go-dongle 0.2.0 版本发布了,一个轻量级、语义化的 golang 编码解码、加密解密库
dongle 是一个轻量级.语义化.对开发者友好的 Golang 编码解码和加密解密库 Dongle 已被 awesome-go 收录, 如果您觉得不错,请给个 star 吧 github.com/g ...