第13章 线程安全与锁优化+字节码解析
1、概述
2、synchronized原理
3、字节码分析
Class组成:
引用参考:https://snailclimb.gitee.io/javaguide/#/docs/java/jvm/%E7%B1%BB%E6%96%87%E4%BB%B6%E7%BB%93%E6%9E%84
举例1:
package com.javabasic.synchronizeds; public class ShareData { int num; public synchronized void increase1() { num++; } public void increase2() { synchronized(this) { num++; } } public void increase3() { synchronized(ShareData.class) { num++; } } public int getNum() { return num; } }
javap -c -l -s -v ShareData.class 命令查看字节码:
Classfile /E:/workspace170208/JavaBasicTest/target/classes/com/javabasic/synchronizeds/ShareData.class Last modified 2020-5-26; size 850 bytes MD5 checksum 666a7a0b1a6ab9b525f32276cb6cd699 Compiled from "ShareData.java" public class com.javabasic.synchronizeds.ShareData minor version: 0 //次版本号 major version: 52 //主版本号 flags: ACC_PUBLIC, ACC_SUPER //访问标志,ACC_PUBLIC是否为public类型, ACC_SUPER是否允许使用invokespecial字节码指令 Constant pool://常量池 #1 = Class #2 // com/javabasic/synchronizeds/ShareData (#2是一个索引值,指向常量池中Utf8类型常量,代表类或接口的全限定名)# #2 = Utf8 com/javabasic/synchronizeds/ShareData #3 = Class #4 // java/lang/Object #4 = Utf8 java/lang/Object #5 = Utf8 num #6 = Utf8 I #7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code // #10 = Methodref #3.#11 // java/lang/Object."<init>":()V (java.lang.Object类的<init>方法) #11 = NameAndType #7:#8 // "<init>":()V #12 = Utf8 LineNumberTable #13 = Utf8 LocalVariableTable #14 = Utf8 this #15 = Utf8 Lcom/javabasic/synchronizeds/ShareData; #16 = Utf8 increase1 #17 = Fieldref #1.#18 // com/javabasic/synchronizeds/ShareData.num:I #18 = NameAndType #5:#6 // num:I #19 = Utf8 increase2 #20 = Utf8 StackMapTable //Code属性,JDK1.5中新增的属性,共新类型检查验证器(Type Checker)检查和处理目标方法的局部变量和操作数栈锁需要的类型是否匹配 #21 = Class #22 // java/lang/Throwable #22 = Utf8 java/lang/Throwable #23 = Utf8 increase3 #24 = Class #25 // java/lang/Class #25 = Utf8 java/lang/Class #26 = Utf8 getNum #27 = Utf8 ()I #28 = Utf8 SourceFile //类文件,记录源文件名称 #29 = Utf8 ShareData.java { int num; descriptor: I flags: public com.javabasic.synchronizeds.ShareData();//默认构造方法 descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #10 // Method java/lang/Object."<init>":()V //调用超类构造方法,实例初始化方法,私有方法 4: return LineNumberTable: line 3: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/javabasic/synchronizeds/ShareData; public synchronized void increase1(); descriptor: ()V flags: ACC_PUBLIC, ACC_SYNCHRONIZED //同步方法标识 Code: //方法表,Java代码遍历成的字节码指令 stack=3, locals=1, args_size=1 0: aload_0 //将第一个引用类型本地变量推送至栈顶 1: dup ///复制栈顶数值并将复制值压入栈顶 2: getfield #17 // Field num:I //获取指定类的实例域,并将其值压入栈顶 5: iconst_1 //将int型1推送至栈顶 6: iadd //将栈顶两个int型数值相加将结果压入栈顶 7: putfield #17 // Field num:I //为指定的类的实例域赋值 10: return //从当前方法返回void LineNumberTable: //Code属性,Java源码的行号与字节码指令的对应关系 line 8: 0 line 9: 10 LocalVariableTable: //Code属性,方法的局部变量描述 Start Length Slot Name Signature 0 11 0 this Lcom/javabasic/synchronizeds/ShareData; public void increase2(); descriptor: ()V flags: ACC_PUBLIC Code: stack=3, locals=2, args_size=1 0: aload_0 //将第一个引用类型本地变量推送至栈顶 1: dup //复制栈顶数值并将复制值压入栈顶 2: astore_1 //将栈顶引用型数值存入第二个本地变量 3: monitorenter //获得对象的锁,用于同步方法或同步块 4: aload_0 //将第二个引用类型本地变量推送至栈顶 5: dup //复制栈顶数值并将复制值压入栈顶 6: getfield #17 // Field num:I //获取指定类的实例域,并将其值压入栈顶 9: iconst_1 //将int型1推送至栈顶 10: iadd //将栈顶两个int型数值相加将结果压入栈顶 11: putfield #17 // Field num:I //为指定的类的实例域赋值 14: aload_1 //将第二个引用类型本地变量推送至栈顶 15: monitorexit //释放对象的锁,用于同步方法或同步块 16: goto 22 //无条件跳转 19: aload_1 //将第二个引用类型本地变量推送至栈顶 20: monitorexit //释放对象的锁,用于同步方法或同步块 21: athrow //将栈顶的异常抛出 22: return Exception table: from to target type 4 16 19 any 19 21 19 any LineNumberTable: line 12: 0 line 13: 4 line 12: 14 line 15: 22 LocalVariableTable: Start Length Slot Name Signature 0 23 0 this Lcom/javabasic/synchronizeds/ShareData; StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 19 locals = [ class com/javabasic/synchronizeds/ShareData, class com/javabasic/synchronizeds/ShareData ] stack = [ class java/lang/Throwable ] frame_type = 250 /* chop */ offset_delta = 2 public void increase3(); descriptor: ()V flags: ACC_PUBLIC Code: stack=3, locals=2, args_size=1 0: ldc #1 // class com/javabasic/synchronizeds/ShareData 2: dup 3: astore_1 4: monitorenter 5: aload_0 6: dup 7: getfield #17 // Field num:I 10: iconst_1 11: iadd 12: putfield #17 // Field num:I 15: aload_1 16: monitorexit 17: goto 23 20: aload_1 21: monitorexit 22: athrow 23: return Exception table: from to target type 5 17 20 any 20 22 20 any LineNumberTable: line 18: 0 line 19: 5 line 18: 15 line 21: 23 LocalVariableTable: Start Length Slot Name Signature 0 24 0 this Lcom/javabasic/synchronizeds/ShareData; StackMapTable: number_of_entries = 2 frame_type = 255 /* full_frame */ offset_delta = 20 locals = [ class com/javabasic/synchronizeds/ShareData, class java/lang/Class ] stack = [ class java/lang/Throwable ] frame_type = 250 /* chop */ offset_delta = 2 public int getNum(); descriptor: ()I flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: getfield #17 // Field num:I 4: ireturn LineNumberTable: line 24: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lcom/javabasic/synchronizeds/ShareData; } SourceFile: "ShareData.java"