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 同步语句块的实现使用的是 monitorentermonitorexit 指令,其中 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 同步语句块的实现使用的是 monitorentermonitorexit 指令,其中 monitorenter 指令指向同步代码块的开始位置,monitorexit 指令则指明同步代码块的结束位置。正常情况下回有两个monitorexit指令,为了在出现异常也能够成功释放锁。

  synchronized 修饰的方法并没有 monitorenter 指令和 monitorexit 指令,取得代之的确实是 ACC_SYNCHRONIZED 标识,该标识指明了该方法是一个同步方法。

  不过两者的本质都是对监视器 monitor 的获取

 

线程基础知识06 synchronized---使用javap查看相关指令的更多相关文章

  1. Java并发编程(一):线程基础知识以及synchronized关键字

    1.线程与多线程的概念:在一个程序中,能够独立运行的程序片段叫作“线程”(Thread).多线程(multithreading)是指从软件或者硬件上实现多个线程并发执行的技术. 2.多线程的意义:多线 ...

  2. java线程基础知识----线程与锁

    我们上一章已经谈到java线程的基础知识,我们学习了Thread的基础知识,今天我们开始学习java线程和锁. 1. 首先我们应该了解一下Object类的一些性质以其方法,首先我们知道Object类的 ...

  3. java线程基础知识----线程基础知识

    不知道从什么时候开始,学习知识变成了一个短期记忆的过程,总是容易忘记自己当初学懂的知识(fuck!),不知道是自己没有经常使用还是当初理解的不够深入.今天准备再对java的线程进行一下系统的学习,希望 ...

  4. Windows核心编程 第六章 线程基础知识 (上)

    第6章 线程的基础知识 理解线程是非常关键的,因为每个进程至少需要一个线程.本章将更加详细地介绍线程的知识.尤其是要讲述进程与线程之间存在多大的差别,它们各自具有什么作用.还要介绍系统如何使用线程内核 ...

  5. Java__线程---基础知识全面实战---坦克大战系列为例

    今天想将自己去年自己编写的坦克大战的代码与大家分享一下,主要面向学习过java但对java运用并不是很熟悉的同学,该编程代码基本上涉及了java基础知识的各个方面,大家可以通过练习该程序对自己的jav ...

  6. Java 线程基础知识

    前言 什么是线程?线程,有时被称为轻量进程(Lightweight Process,LWP),是程序执行流的最小单元.一个标准的线程由线程 ID,当前指令指针 (PC),寄存器集合和堆栈组成.另外,线 ...

  7. Windows核心编程 第六章 线程基础知识 (下)

    6.6 线程的一些性质 到现在为止,讲述了如何实现线程函数和如何让系统创建线程以便执行该函数.本节将要介绍系统如何使这些操作获得成功. 图6 - 1显示了系统在创建线程和对线程进行初始化时必须做些什么 ...

  8. 基础知识系列☞Abstract和Virtual→及相关知识

    转载地址→http://www.cnblogs.com/blsong/archive/2010/08/12/1798064.html 在C#的学习中,容易混淆virtual方法和abstract方法的 ...

  9. Java多线程系列 基础篇06 synchronized(同步锁)

    转载 http://www.cnblogs.com/paddix/ 作者:liuxiaopeng http://www.infoq.com/cn/articles/java-se-16-synchro ...

  10. Java并发之线程管理(线程基础知识)

    因为书中涵盖的知识点比较全,所以就以书中的目录来学习和记录.当然,学习书中知识的时候自己的思考和实践是最重要的.说到线程,脑子里大概知道是个什么东西,但很多东西都还是懵懵懂懂,这是最可怕的.所以想着细 ...

随机推荐

  1. Go语言核心36讲36

    在前面,我几乎已经把Go语言自带的同步工具全盘托出了.你是否已经听懂了会用了呢? 无论怎样,我都希望你能够多多练习.多多使用.它们和Go语言独有的并发编程方式并不冲突,相反,配合起来使用,绝对能达到& ...

  2. CSS伪类使用详解

    基本描述 CSS伪类是很常用的功能,主要应用于选择器的关键字,用来改变被选择元素的特殊状态下的样式. 伪类类似于普通CSS类的用法,是对CSS选择器的一种扩展,增强选择器的功能. 目前可用的伪类有大概 ...

  3. 数电第7周周结_by_yc

    一.通用双向移位寄存器: 功能描述:   4位的双向移位寄存器,含控制输入端(ctrl).串行输入端(Dsl.Dsr).4个并行输入端和4个并行输出端,要求实现5种功能:异步置零.同步置数.左移.右移 ...

  4. 深入浅出学习透析 Nginx 服务器的基本原理和配置指南「运维操作实战篇」

    Nginx前提回顾 Nginx 是一个高性能的 Web 和反向代理服务器, 它具有有很多非常优越的特性: Web服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效 ...

  5. 【Java技术】String类的使用

    属于引用类型,在java.lang包下,类似的还有Integer.Character.Boolean.Math 常用方法: char charAt(int index)返回 char指定索引处的值. ...

  6. ChatGPT 会开源吗?

    最近,我被一款叫做 ChatGPT 的人工智能(AI)聊天机器人,刷屏了.网上有人说它是搜索引擎杀手,还有人说它将取代程序员... 最后,我还是没扛住铺天盖地的赞美,跑去注册了个账号,抱着调侃&quo ...

  7. O-MVLL:支持ARM64的基于LLVM的代码混淆模块

    O-MVLL介绍 O-MVLL的开发灵感来自于另一个著名的基于LLVM的代码混淆项目ollvm,并在其基础上做了创新和改进.O-MVLL的混淆逻辑实现方式也是通过LLVM Pass,支持也仅会支持AR ...

  8. 同步与异步 multiprocessing 进程对象多种方法

    目录 同步与异步 阻塞与非阻塞 综合使用 创建进程的多种方式 前言 windows系统创建进程的问题(重要) multiprocessing模块之Process 展现异步 创建进程的方式(一):使用P ...

  9. Flask框架(flask-sqlalchemy操作,Migrate作用,Flask迁移数据库,Flaks同步表数据)

    目录 一:flask-sqlalchemy操作 1.引入: 2.Flask-Migrate扩展 3.flask-sqlalchemy与slask_migrate作用 4.flask-migrate初始 ...

  10. JavaScript:代码应该编写在哪里?

    我们可以将JS的代码,编写在三个地方. 但是无论编写在哪里,最后它都会嵌入进网页代码中,被浏览器执行. 编写在script标签中 我们可以直接在HTML的script标签中,编写大段JS代码. 编写在 ...