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

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

然后用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.class
Last modified Sep 11, 2018; size 831 bytes
MD5 checksum 22c52151c374d39068e39938d1b3e72c
Compiled from "MyTest2.java"
public class com.jvm.bytecode.MyTest2
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #10.#34 // java/lang/Object."<init>":()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."<init>":()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 <init>
#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 <clinit>
#32 = Utf8 SourceFile
#33 = Utf8 MyTest2.java
#34 = NameAndType #17:#18 // "<init>":()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_STATIC public com.jvm.bytecode.MyTest2();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: ldc #2 // String Welcome
7: putfield #3 // Field str:Ljava/lang/String;
10: aload_0
11: iconst_5
12: putfield #4 // Field x:I
15: return
LineNumberTable:
line 3: 0
line 4: 4
line 6: 10
LocalVariableTable:
Start Length Slot Name Signature
0 16 0 this Lcom/jvm/bytecode/MyTest2; public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: new #5 // class com/jvm/bytecode/MyTest2
3: dup
4: invokespecial #6 // Method "<init>":()V
7: astore_1
8: aload_1
9: bipush 8
11: invokevirtual #7 // Method setX:(I)V
14: bipush 20
16: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
19: putstatic #9 // Field in:Ljava/lang/Integer;
22: return
LineNumberTable:
line 11: 0
line 13: 8
line 15: 14
line 16: 22
LocalVariableTable:
Start Length Slot Name Signature
0 23 0 args [Ljava/lang/String;
8 15 1 myTest2 Lcom/jvm/bytecode/MyTest2; public void setX(int);
descriptor: (I)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: iload_1
2: putfield #4 // Field x:I
5: return
LineNumberTable:
line 19: 0
line 20: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/jvm/bytecode/MyTest2;
0 6 1 x I static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: bipush 10
2: invokestatic #8 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
5: putstatic #9 // Field in:Ljava/lang/Integer;
8: return
LineNumberTable:
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;)V
flags: ACC_PRIVATE
Code:
stack=3, locals=4, args_size=2
0: aload_1
1: dup
2: astore_2
3: monitorenter
4: getstatic #10 // Field java/lang/System.out:Ljava/io/PrintStream;
7: ldc #11 // String hello world~
9: iconst_0
10: anewarray #12 // class java/lang/Object
13: invokevirtual #13 // Method java/io/PrintStream.printf:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream;
16: pop
17: aload_2
18: monitorexit
19: goto 27
22: astore_3
23: aload_2
24: monitorexit
25: aload_3
26: athrow
27: return
Exception table:
from to target type
4 19 22 any
22 25 22 any
LineNumberTable:
line 23: 0
line 24: 4
line 25: 17
line 26: 27
LocalVariableTable:
Start Length Slot Name Signature
0 28 0 this Lcom/jvm/bytecode/MyTest2;
0 28 1 str Ljava/lang/String;
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 22
locals = [ 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。

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

synchronized关键字所生成的字节码详细分析的更多相关文章

  1. JVM synchronized关键字所生成的字节码

    一.创建测试类 package com.example.jvm.bytecode; public class MyTest2 { String str = "Welcome"; p ...

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

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

  3. eclipse中的项目无法在build/classes目录下生成.class字节码

    转载 原文链接:https://www.cnblogs.com/iceblow/p/6648715.html 1.首先确定project->Build Automatically是否勾选上:  ...

  4. LinkedHashMap 源码详细分析(JDK1.8)

    1. 概述 LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题.除此之外,Linke ...

  5. 反编译字节码角度分析synchronized关键字的原理

    1.synchronized介绍 synchronized是java关键字.JVM规范中,synchronized关键字用于在线程并发执行时,保证同一时刻,只有一个线程可以执行某个代码块或方法:同时还 ...

  6. 基于ASP.NET生成二维码详细源码

    详细链接:https://shop499704308.taobao.com/?spm=a1z38n.10677092.card.11.594c1debsAGeakusing System; using ...

  7. HashMap 源码详细分析(JDK1.8)

    一.概述 本篇文章我们来聊聊大家日常开发中常用的一个集合类 - HashMap.HashMap 最早出现在 JDK 1.2中,底层基于散列算法实现.HashMap 允许 null 键和 null 值, ...

  8. ArrayList 源码详细分析

    1.概述 ArrayList 是一种变长的集合类,基于定长数组实现.ArrayList 允许空值和重复元素,当往 ArrayList 中添加的元素数量大于其底层数组容量时,其会通过扩容机制重新生成一个 ...

  9. DownloadProvider 源码详细分析

    DownloadProvider 简介 DownloadProvider 是Android提供的DownloadManager的增强版,亮点是支持断点下载,提供了“开始下载”,“暂停下载”,“重新下载 ...

随机推荐

  1. 02点睛Spring MVC 4.1-@RequestMapping

    转发地址:https://www.iteye.com/blog/wiselyman-2213907 2.1 @RequestMapping @RequestMapping是SpringMVC的核心注解 ...

  2. 推荐两本CCF教材

    希望学习电脑程序设计的同学,可以购买如下两本教材,先学习入门篇,再学习基础篇.淘宝.当当.京东均有售.建议选择比较靠谱的网店,避免买到盗版书.

  3. centOS安装配置NFS

    环境 nfs 192.168.56.101 client 192.168.56.102 一.yum 安装 yum -y install nfs-utils rpcbind 192.168.56.101 ...

  4. xadmin自定义菜单、增加功能、富文本编辑器

    xadmin功能:https://www.cnblogs.com/derek1184405959/p/8682250.html#blogTitle7

  5. php有关类和对象的相关知识1

    有关类和对象的相关知识 类的自动加载 类的自动加载是指,在外面的页面中,并不需要去“引入”(包含)类文件,但是程序会在需要一个类的时候就自动去“动态加载”该类. 什么叫做“需要一个类”?通常是这样的情 ...

  6. xticks,yticks

    原本的图片如下所示: 如果加上这样的语句: import matplotlib.pyplot as plt plt.xticks([]),plt.yticks([]) 显示结果就为:

  7. linux 编程 如何判断socket断开???--ongoing

    1 利用select ? 2从github上找例子 3 学习asio  c++ library

  8. Mybatis笔记1

    Mybatis 持久层框架,数据访问层 mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动,创建连接,创建sta ...

  9. C之推栈溢出原因

    https://blog.csdn.net/weixin_36194037/article/details/78871468

  10. Python10之列表1(创建列表和列表添加元素的方法)

    一.创建列表 列表名 = [’元素一‘,’元素二‘,’元素三‘,’元素四‘] 列表中的元素可以是任何类型,甚至可以是一个列表. list1 = ['詹姆斯','戴维斯','保罗乔治','字母哥',in ...