java并发之synchronized深入学习记录(一)

java并发之synchronized深入学习记录

synchronized关键字是java中很常用的一种关键字,但是大多数人还是停留在会用的基础上,对于synchronized关键字的底层的原理实现还是一知半解,作为java中一个很常用也很重要的关键字,synchronized的底层实现对于加速并发深入了解起到了很大的作用。

1.synchronized常用的场景

	普通同步方法(实例方法),锁是当前实例对象 ,进入同步代码前要获得当前实例的锁
//java普通同步方法,默认取得就是当前对象
public  synchronized void method1() {
		System.out.println("普通同步方法")
}
	静态同步方法,锁是当前类的class对象 ,进入同步代码前要获得当前类对象的锁
//java普通同步方法,默认取得就是当前对象
public static synchronized void method2() {
		System.out.println("当前类class对象的同步方法")
}
	同步方法块,锁是括号里面的对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁
public void method3() {
		//this对象可以换成任何一个对象,默认this就是当前对象本身
		synchronized(this) {
			System.out.println("同步方法块")
		}
	}
	

2.synchronized关键字不同用法下的反编译

上述三种为大家常用的方法,下面我一步步将上面的三种方法进行反编译,看看反编译之后的代码是怎样的
下面展示一下同步代码块方法:

public void method1();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=1
         0: aload_0
         1: dup
         2: astore_1
         3: monitorenter
         4: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
         7: ldc           #21                 // String Hello World!
         9: invokevirtual #23                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        12: aload_1
        13: monitorexit
        14: goto          20
        17: aload_1
        18: monitorexit
        19: athrow

反编译之后,大家可以从上述的指令集中看到monitorentermonitorexit这两个指令,下面我来解释一下这两个指令集的意思

  1. monitorenter:monitorenter指向一个对象,这个对象里面放着锁的各种信息和重入次数,当一个线程执行到monitorenter这个指令的时候,这个线程会尝试获取该对象的monitor所有权,获取成功了,就表示持有了这把锁,同时monitor的进入次数加1,如果是多次重入,则会多次加1。
  2. monitorexit:monitorexit在方法的结束的地方,每次执行重入次数都会减1,直到结束重入次数为0,也就表示持有锁的线程释放了这把锁,上述字节码文件存在两个monitorexit,这是jvm在程序发生异常的处理过程中,由jvm加的一个monitorexit。

下面展示一下普通同步方法:


  public synchronized void method1();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #21                 // String Hello World!
         5: invokevirtual #23                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
      LineNumberTable:
        line 6: 0
        line 7: 8
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       9     0  this   Lcom/test/netty/SynchronizedTest;
}

反编译之后似乎并没有看见monitorentermonitorexit,到这里有些人就比较疑惑了,虽然这段字节码指令中并没有看见这两个字段,但是却有一个新的指令ACC_SYNCHRONIZED,看到这个指令是不是比较眼熟,确实,这个指令和我们java中的同步关键字synchronized很像,JVM就是通过这个标识符来实现方法同步的。

  1. 当同步方法被调用时,jvm将会检查该方法的 ACC_SYNCHRONIZED是否被设置,如果设置了,线程将会直接访问当前对象的monitor,所以同步方法本质上其实还是调用monitor.

静态同步方法


public static synchronized void method3();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #15                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: sipush        1111
         6: invokevirtual #21                 // Method java/io/PrintStream.println:(I)V
         9: return
      LineNumberTable:
        line 8: 0
        line 10: 9
      LocalVariableTable:
        Start  Length  Slot  Name   Signature

上述字节码文件大家发现没有,其实和普通同步方法并没有什么区别,只是多了一个静态字节码指令,所以调用的本质还是一样的,这里就不多做解释了。

今天的学习记录就写到这里,如果有兴趣的话,可以继续看下一篇文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值