1.synchronized介绍

  synchronized是java关键字。JVM规范中,synchronized关键字用于在线程并发执行时,保证同一时刻,只有一个线程可以执行某个代码块或方法;同时还保证了代码在执行完后所修改的数据对其它线程是可见的。总结来说:synchronized解决了并发编程安全问题的原子性,可见性,顺序行。Java中每一个对象都可以作为锁(monitor),这是synchronized实现同步的基础。synchronized作用于每一个对象时,要求占有当前对象的锁要么没有任何线程占用,或者是当前线程占用,这样该线程才能获得该对象的访问权,一旦某个线程获得对象的访问权,其它线程就会因为无法获得访问权限而进入阻塞状态。synchronized可用于3种情况:

(1)普通同步方法(实例方法),锁是当前实例对象 ,进入同步代码前要获得当前实例的锁
(2)静态同步方法,锁是当前类的Class对象 ,进入同步代码前要获得当前类的Class对象的锁
(3)同步方法块,锁是括号里面的对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。
那么就以这3种情况分析下反编译后得字节码,看看有synchronized修饰的代码块有何不同之处

2.反编译字节码分析synchronized

  下面是含有3中情况的一个demo源码

public class TestSynchornize {

    /**
* 修饰静态方法
*/
public synchronized static void test1() {
System.out.println("test1");
} /**
* 修饰实例方法
*/
public synchronized void test2(){
System.out.println("test2");
} /**
* 修饰代码块
*/
public void test3(){
synchronized (this){
System.out.println("test3");
}
}
}

  用 javap 命令反编译字节码TestSynchornize.class,截图三种情况字节码如下:

静态方法

实例方法

代码块

(1)首先,可以看到在反编译代码块那里的字节码中可以看到其中有一个monitorenter指令和两个monitorexit指令。其实这就是synchronized的关键所在,synchronized修饰的代码块会带有monitorenter和monitorexit指令,用于jvm中控制同步代码块访问时必须获得对象锁。那么这里为啥会有两个monitorexit指令,获取对象锁执行完代码后不是释放对象锁就行了吗?按理来说monitorenter和monitorexit应该是一对一的?这里就是关键所在,JVM为了防止异常,获得锁的线程无法释放的情况,规定了synchronized锁修饰的代码块当线程执行异常时,会自动释放对象锁。因此这里有两个monitorexit指令,分别对应正常释放和异常释放。

(2)可以看到在修饰静态方法和实例方法那里并没有monitorenter和monitorexit指令。但是可以观察到在方法的访问flags那里都有ACC_SYNCHRONIZED修饰。其实这里也是会用到monitorenter和monitorexit,只不过在修饰方法时用ACC_SYNCHRONIZED代替了。再加上ACC_STATIC就可以判断是静态方法还是实例方法了,后面拿到需要获取的所对象,实现方式就跟代码块那里一样了。

3.总结

  synchronized之所以是JVM层实现的同步控制的,原因在于代码编译中就加入了monitorenter和monitorexit指令控制同步访问,各个JVM厂商按照jvm规范实现该指令。

注意:本文仅代表个人理解和看法哟!和本人所在公司和团体无任何关系!

反编译字节码角度分析synchronized关键字的原理的更多相关文章

  1. 【synchronized锁】通过synchronized锁 反编译查看字节码指令分析synchronized关键字修饰方法与代码块的区别

    前提: 首先要铺垫几个前置的知识: Java中的锁如sychronize锁是对象锁,Java对象头中具有标识位,当对象锁升级为重量级锁时,重量级锁的标识位会指向监视器monitor, 而每个Java对 ...

  2. 从字节码角度分析Byte类型变量b++和++b

    1. 下面是一到Java笔试题: public class Test2 { public void add(Byte b) { b = b++; } public void test() { Byte ...

  3. IDEA设置External Tools之Javap反编译字节码

    通过Jdk的命令javap可以反编译查看字节码,但是在使用idea的时候一直用命令行去操作不太好操作,而且因为idea会把class码 放在target里面,经常会忘记切换目录.这个时候idea的Ex ...

  4. 源码角度分析-newFixedThreadPool线程池导致的内存飙升问题

    前言 使用无界队列的线程池会导致内存飙升吗?面试官经常会问这个问题,本文将基于源码,去分析newFixedThreadPool线程池导致的内存飙升问题,希望能加深大家的理解. (想自学习编程的小伙伴请 ...

  5. synchronized关键字所生成的字节码详细分析

    在之前已经将如下这样的源文件对应的字节码文件完整的分析完了,如下: 这次再来写一个内容稍丰富一点的类,准备再来从头至尾的来分析一下,对其字节码的理解进一步巩固,如下: 然后用javap -verbos ...

  6. 从java字节码角度看线程安全性问题

    先看代码: package com.roocon.thread.t3; public class Sequence { private int value; public int getNext(){ ...

  7. 自修改代码 on the fly 动态编译 即时编译 字节码

    https://zh.wikipedia.org/wiki/自修改代码 自修改代码(Self-modifying code)是指程序在运行期间(Run time)修改自身指令.可能的用途有:病毒利用此 ...

  8. JAVA面试题 StringBuffer和StringBuilder的区别,从源码角度分析?

    面试官Q1:请问StringBuffer和StringBuilder有什么区别? 这是一个老生常谈的话题,笔者前几年每次面试都会被问到,作为基础面试题,被问到的概率百分之八九十.下面我们从面试需要答到 ...

  9. mac 环境下Android 反编译源码

    mac环境下Android 反编译 一.需要的工具 apktool:反编译APK文件,得到classes.dex文件,同时也能获取到资源文件以及布局文件. dex2jar:将反编译后的classes. ...

随机推荐

  1. Error in execution; nested exception is io.lettuce.core.RedisCommandExecutionException: ERR invalid longitude,latitude pair 111.110000,111.230000

    io.lettuce.core.RedisCommandExecutionException: ERR invalid longitude,latitude pair 111.110000,111.2 ...

  2. 【Elasticsearch 7 探索之路】(六)初识 Mapping

    上一篇主要讲解什么是 URL Search 和 Request Body Search 的语法.本篇对 Mapping 的 Dynamic Mapping 以及手动创建 Mapping 进行讲解. 1 ...

  3. 快速上手的Glide4.x教程

    安卓基础开发库,让开发简单点. DevRing & Demo地址:https://github.com/LJYcoder/DevRing 学习/参考地址: https://blog.csdn. ...

  4. std::wcout输出1遍不输出

    std::wcout输出1遍不输出 程序明明在执行地方执行 wcout无法输出到控制台 cout就可以 添加中文支持即可

  5. js 实现弹出层效果

    代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <tit ...

  6. Java IO之处理流

    一.处理流: 增强功能,提供性能,在节点流之上. 二.节点流与处理流的关系 节点流(字节流.字符流)处于IO操作的第一线,所有操作必须通过它们进行: 处理流可以对其他流进行处理(提高效率或操作灵活性) ...

  7. MySQL常规操作以及问题

    背景 作为一个前端,偶尔搞下后端 要熟悉 SQL 操作,但是一段时间不用 会大部分忘记,之后又要重新查资料 所以自己整理一遍经常用到的 SQL 操作 和使用过程遇到的问题,方便自己快速查阅 一.安装 ...

  8. 基础(一):SCSI硬盘与IDE硬盘有什么区别

    硬盘接口是硬盘与主机系统间的连接部件,作用是在硬盘缓存和主机内存之间传输数据.不同的硬盘接口决定着硬盘与计算机之间的连接速度,在整个系统中,硬盘接口的优劣直接影响着程序运行快慢和系统性能好坏.从整体的 ...

  9. centos7 安装telent和telnet-server

    安装centos7 无telnet命令 先检查CentOS7.0是否已经安装以下两个安装包:telnet-server.xinetd.命令如下: rpm -q telnet-server rpm -q ...

  10. (9)centos7 安装与解压

    1.zip/unzip zip 新file 旧file或文件夹 # 把旧文件和文件夹压缩成新文件 -r是文件夹下所有文件 zip -r a.zip ./doc #压缩当前目录 doc下的所有文件变成 ...