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. 学习ASP.NET Core Blazor编程系列十——路由(中)

    学习ASP.NET Core Blazor编程系列一--综述 学习ASP.NET Core Blazor编程系列二--第一个Blazor应用程序(上) 学习ASP.NET Core Blazor编程系 ...

  2. 在 Spring 生态中玩转 RocketMQ

    本文作者:饶子昊 - Spring Cloud Alibaba Committer,阿里云智能开发工程师. 01 Spring 生态介绍 根据 JVM EcoSystem Report 2021 最新 ...

  3. JDK17都出了,学点JDK11新特性

    JDK8 - 转- JDK11 -转- JDK17 JShell(JDK9开始支持) G:\dowload\JDK\JDK11\jdk-11.0.2\bin ===> C:\Windows\Sy ...

  4. Solon v1.11.0 发布,Hello Java

    一个更现代感的 Java 应用开发框架:更快.更小.更自由.没有 Spring,没有 Servlet,没有 JavaEE:独立的轻量生态.主框架仅 0.1 MB. @Controller public ...

  5. JavaScript笔记之面向对象

    面向对象 了解构造函数原型对象的语法特征,掌握 JavaScript 中面向对象编程的实现方式,基于面向对象编程思想实现 DOM 操作的封装. 了解面向对象编程的一般特征 掌握基于构造函数原型对象的逻 ...

  6. nginx压力测试及限速

    测试工具:Apache ab windows安装教程:https://www.cnblogs.com/laijinquan/p/14694655.html 64位下载地址:https://www.ap ...

  7. WeakHashMap 和 HashMap 的区别是什么,何时使用?

    本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问. 前言 大家好,我是小彭. 在之前的文章里,我们聊到了 Java 标准库中 HashMap 与 LinkedH ...

  8. 【Shell案例】【!~//、grep反向查找、sed流编辑器】13、去掉所有包含this的句子

    描述写一个 bash脚本以实现一个需求,去掉输入中含有this的语句,把不含this的语句输出示例:假设输入如下:that is your bagis this your bag?to the deg ...

  9. 【Java SE】Day06 类与对象、封装和构造方法

    一.面向对象思想 1.概述:调用对象的行为实现功能,无需一步一步实现(从执行者变成指挥者) 2.类和对象 类是属性和行为的集合,可以看成描述事物的模板 对象是事物的具体体现,是类的一个实例,具备该类的 ...

  10. 【课程复习】Java Web、框架及项目简单回顾

    JavaEE Day14 Servlet&HTTP&Request&BeanUtils介绍 Servlet类体系结构,两个子抽象类,需要继承HttpServlet而不是Gene ...