第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"
原文地址:https://www.cnblogs.com/wangymd/p/12966281.html