热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

在之前已经将如下这样的源文件对应的字节码文件完整的分析完了,如下:这次再来写一个内容稍丰富一点的类,准备再来从头至尾的来分析一下ÿ

在之前已经将如下这样的源文件对应的字节码文件完整的分析完了,如下:

这次再来写一个内容稍丰富一点的类,准备再来从头至尾的来分析一下,对其字节码的理解进一步巩固,如下:

然后用javap -verbose来查看一下反编译信息:

xiongweideMacBook-Pro:jvm_lectue xiongwei$ cd out/production/classes/
xiongweideMacBook-Pro:classes xiongwei$ javap -verbose com/jvm/bytecode/MyTest2.class
Classfile /Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes/com/jvm/bytecode/MyTest2.classLast modified Sep 11, 2018; size 831 bytesMD5 checksum 22c52151c374d39068e39938d1b3e72cCompiled from "MyTest2.java"
public class com.jvm.bytecode.MyTest2minor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER
Constant pool:#1 = Methodref #10.#34 // java/lang/Object."":()V#2 = String #35 // Welcome#3 = Fieldref #5.#36 // com/jvm/bytecode/MyTest2.str:Ljava/lang/String;#4 = Fieldref #5.#37 // com/jvm/bytecode/MyTest2.x:I#5 = Class #38 // com/jvm/bytecode/MyTest2#6 = Methodref #5.#34 // com/jvm/bytecode/MyTest2."":()V#7 = Methodref #5.#39 // com/jvm/bytecode/MyTest2.setX:(I)V#8 = Methodref #40.#41 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;#9 = Fieldref #5.#42 // com/jvm/bytecode/MyTest2.in:Ljava/lang/Integer;#10 = Class #43 // java/lang/Object#11 = Utf8 str#12 = Utf8 Ljava/lang/String;#13 = Utf8 x#14 = Utf8 I#15 = Utf8 in#16 = Utf8 Ljava/lang/Integer;#17 = Utf8 #18 = Utf8 ()V#19 = Utf8 Code#20 = Utf8 LineNumberTable#21 = Utf8 LocalVariableTable#22 = Utf8 this#23 = Utf8 Lcom/jvm/bytecode/MyTest2;#24 = Utf8 main#25 = Utf8 ([Ljava/lang/String;)V#26 = Utf8 args#27 = Utf8 [Ljava/lang/String;#28 = Utf8 myTest2#29 = Utf8 setX#30 = Utf8 (I)V#31 = Utf8 #32 = Utf8 SourceFile#33 = Utf8 MyTest2.java#34 = NameAndType #17:#18 // "":()V#35 = Utf8 Welcome#36 = NameAndType #11:#12 // str:Ljava/lang/String;#37 = NameAndType #13:#14 // x:I#38 = Utf8 com/jvm/bytecode/MyTest2#39 = NameAndType #29:#30 // setX:(I)V#40 = Class #44 // java/lang/Integer#41 = NameAndType #45:#46 // valueOf:(I)Ljava/lang/Integer;#42 = NameAndType #15:#16 // in:Ljava/lang/Integer;#43 = Utf8 java/lang/Object#44 = Utf8 java/lang/Integer#45 = Utf8 valueOf#46 = Utf8 (I)Ljava/lang/Integer;
{java.lang.String str;descriptor: Ljava/lang/String;flags:public static java.lang.Integer in;descriptor: Ljava/lang/Integer;flags: ACC_PUBLIC, ACC_STATICpublic com.jvm.bytecode.MyTest2();descriptor: ()Vflags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."":()V4: aload_05: ldc #2 // String Welcome7: putfield #3 // Field str:Ljava/lang/String;10: aload_011: iconst_512: putfield #4 // Field x:I15: returnLineNumberTable:line 3: 0line 4: 4line 6: 10LocalVariableTable:Start Length Slot Name Signature0 16 0 this Lcom/jvm/bytecode/MyTest2;public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=2, args_size=10: new #5 // class com/jvm/bytecode/MyTest23: dup4: invokespecial #6 // Method "":()V7: astore_18: aload_19: bipush 811: invokevirtual #7 // Method setX:(I)V14: bipush 2016: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;19: putstatic #9 // Field in:Ljava/lang/Integer;22: returnLineNumberTable:line 11: 0line 13: 8line 15: 14line 16: 22LocalVariableTable:Start Length Slot Name Signature0 23 0 args [Ljava/lang/String;8 15 1 myTest2 Lcom/jvm/bytecode/MyTest2;public void setX(int);descriptor: (I)Vflags: ACC_PUBLICCode:stack=2, locals=2, args_size=20: aload_01: iload_12: putfield #4 // Field x:I5: returnLineNumberTable:line 19: 0line 20: 5LocalVariableTable:Start Length Slot Name Signature0 6 0 this Lcom/jvm/bytecode/MyTest2;0 6 1 x Istatic {};descriptor: ()Vflags: ACC_STATICCode:stack=1, locals=0, args_size=00: bipush 102: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;5: putstatic #9 // Field in:Ljava/lang/Integer;8: returnLineNumberTable:line 8: 0
}
SourceFile: "MyTest2.java"

由于这次的类中声明有静态变量,所以标红处多了一个static块,下面将“-verbose”参数去掉可以看到一个更精简的信息,如下:

其中注意此时有一个setX()方法的,那如果将setX()方法访问修饰符由“public”改为"private",看会发生啥:

为啥呢?其实并非私有的方法在字节码信息中就不存在了,而是用javap命令需要再加一个参数才能看到私有的方法,如下:

由于此篇讨论的话题是关于synchronized关键字在字节码中的含义,所以接下来咱们给setX()方法加一个同步锁然后再来分析其字节码,在加之前先来看下不带synchronized所对应字节码的信息,如下:

接下来给方法加上synchronized,如下:

然后看一下此时对应的字节码会发生啥变化:

貌似网上有很多资料看到对于同步方法在字节码中表现通常会有“moniterenter”和“moniterexit”,但是为啥咱们自己通过javap -verbose查看不到呢?因为修饰的是实例方法,也就是给当前对象上锁,表现则是在方法说明之上而非代码中,如果改为修饰方法中的代码的话则就会可以看到啦,如下:

当然上面的这个是对参数str进行上锁,实际没啥意义,因为str是一个可变的值,正常的做法应该是对一个不可变的对象进行上锁,这里只是为了说明问题,下面再来看一下字节码信息:

private void test(java.lang.String);descriptor: (Ljava/lang/String;)Vflags: ACC_PRIVATECode:stack=3, locals=4, args_size=20: aload_11: dup2: astore_23: monitorenter4: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;7: ldc #11 // String hello world~9: iconst_010: anewarray #12 // class java/lang/Object13: invokevirtual #13 // Method java/io/PrintStream.printf:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;16: pop17: aload_218: monitorexit19: goto 2722: astore_323: aload_224: monitorexit25: aload_326: athrow27: returnException table:from to target type4 19 22 any22 25 22 anyLineNumberTable:line 23: 0line 24: 4line 25: 17line 26: 27LocalVariableTable:Start Length Slot Name Signature0 28 0 this Lcom/jvm/bytecode/MyTest2;0 28 1 str Ljava/lang/String;StackMapTable: number_of_entries = 2frame_type = 255 /* full_frame */offset_delta = 22locals = [ class com/jvm/bytecode/MyTest2, class java/lang/String, class java/lang/Object ]stack = [ class java/lang/Throwable ]frame_type = 250 /* chop */offset_delta = 4

确实是看到了monitorenter,monitorexit了,其加了同步锁在字节码的流程可以大致分析一下:

另外synchronized还可以修饰静态方法,下面写一个:

很显然它锁的是整个class对象,下面也来看一下它对应的字节码信息:

由于synchronized修饰的是方法,而非它里面的代码,所以在javap中只看到了方法签名上有同步信息。

关于同步锁需要了解一下如下概念:重入锁:所谓重入锁就是说同一个线程可以访问多个同步方法,比如说:

访问一次同步方法其引用计数就加1,像上面的引用计数就会变为2,而当setB()执行完之后,则引用计数就会减为1,再setX()执行完则引用计数会减为0。

非重入锁:是指多个线程而言的,比如一个线程访问了一个同步方法,另一个线程再访问同一个对象的该方法则会阻塞。


推荐阅读
  • 纠正网上的错误:自定义一个类叫java.lang.System/String的方法
    本文纠正了网上关于自定义一个类叫java.lang.System/String的错误答案,并详细解释了为什么这种方法是错误的。作者指出,虽然双亲委托机制确实可以阻止自定义的System类被加载,但通过自定义一个特殊的类加载器,可以绕过双亲委托机制,达到自定义System类的目的。作者呼吁读者对网上的内容持怀疑态度,并带着问题来阅读文章。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • ***byte(字节)根据长度转成kb(千字节)和mb(兆字节)**parambytes*return*publicstaticStringbytes2kb(longbytes){ ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
author-avatar
Android代码
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有