反编译字节码角度分析synchronized关键字的原理
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关键字的原理的更多相关文章
- 【synchronized锁】通过synchronized锁 反编译查看字节码指令分析synchronized关键字修饰方法与代码块的区别
前提: 首先要铺垫几个前置的知识: Java中的锁如sychronize锁是对象锁,Java对象头中具有标识位,当对象锁升级为重量级锁时,重量级锁的标识位会指向监视器monitor, 而每个Java对 ...
- 从字节码角度分析Byte类型变量b++和++b
1. 下面是一到Java笔试题: public class Test2 { public void add(Byte b) { b = b++; } public void test() { Byte ...
- IDEA设置External Tools之Javap反编译字节码
通过Jdk的命令javap可以反编译查看字节码,但是在使用idea的时候一直用命令行去操作不太好操作,而且因为idea会把class码 放在target里面,经常会忘记切换目录.这个时候idea的Ex ...
- 源码角度分析-newFixedThreadPool线程池导致的内存飙升问题
前言 使用无界队列的线程池会导致内存飙升吗?面试官经常会问这个问题,本文将基于源码,去分析newFixedThreadPool线程池导致的内存飙升问题,希望能加深大家的理解. (想自学习编程的小伙伴请 ...
- synchronized关键字所生成的字节码详细分析
在之前已经将如下这样的源文件对应的字节码文件完整的分析完了,如下: 这次再来写一个内容稍丰富一点的类,准备再来从头至尾的来分析一下,对其字节码的理解进一步巩固,如下: 然后用javap -verbos ...
- 从java字节码角度看线程安全性问题
先看代码: package com.roocon.thread.t3; public class Sequence { private int value; public int getNext(){ ...
- 自修改代码 on the fly 动态编译 即时编译 字节码
https://zh.wikipedia.org/wiki/自修改代码 自修改代码(Self-modifying code)是指程序在运行期间(Run time)修改自身指令.可能的用途有:病毒利用此 ...
- JAVA面试题 StringBuffer和StringBuilder的区别,从源码角度分析?
面试官Q1:请问StringBuffer和StringBuilder有什么区别? 这是一个老生常谈的话题,笔者前几年每次面试都会被问到,作为基础面试题,被问到的概率百分之八九十.下面我们从面试需要答到 ...
- mac 环境下Android 反编译源码
mac环境下Android 反编译 一.需要的工具 apktool:反编译APK文件,得到classes.dex文件,同时也能获取到资源文件以及布局文件. dex2jar:将反编译后的classes. ...
随机推荐
- 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 ...
- 【Elasticsearch 7 探索之路】(六)初识 Mapping
上一篇主要讲解什么是 URL Search 和 Request Body Search 的语法.本篇对 Mapping 的 Dynamic Mapping 以及手动创建 Mapping 进行讲解. 1 ...
- 快速上手的Glide4.x教程
安卓基础开发库,让开发简单点. DevRing & Demo地址:https://github.com/LJYcoder/DevRing 学习/参考地址: https://blog.csdn. ...
- std::wcout输出1遍不输出
std::wcout输出1遍不输出 程序明明在执行地方执行 wcout无法输出到控制台 cout就可以 添加中文支持即可
- js 实现弹出层效果
代码: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <tit ...
- Java IO之处理流
一.处理流: 增强功能,提供性能,在节点流之上. 二.节点流与处理流的关系 节点流(字节流.字符流)处于IO操作的第一线,所有操作必须通过它们进行: 处理流可以对其他流进行处理(提高效率或操作灵活性) ...
- MySQL常规操作以及问题
背景 作为一个前端,偶尔搞下后端 要熟悉 SQL 操作,但是一段时间不用 会大部分忘记,之后又要重新查资料 所以自己整理一遍经常用到的 SQL 操作 和使用过程遇到的问题,方便自己快速查阅 一.安装 ...
- 基础(一):SCSI硬盘与IDE硬盘有什么区别
硬盘接口是硬盘与主机系统间的连接部件,作用是在硬盘缓存和主机内存之间传输数据.不同的硬盘接口决定着硬盘与计算机之间的连接速度,在整个系统中,硬盘接口的优劣直接影响着程序运行快慢和系统性能好坏.从整体的 ...
- centos7 安装telent和telnet-server
安装centos7 无telnet命令 先检查CentOS7.0是否已经安装以下两个安装包:telnet-server.xinetd.命令如下: rpm -q telnet-server rpm -q ...
- (9)centos7 安装与解压
1.zip/unzip zip 新file 旧file或文件夹 # 把旧文件和文件夹压缩成新文件 -r是文件夹下所有文件 zip -r a.zip ./doc #压缩当前目录 doc下的所有文件变成 ...