Java并发-synchronized原理分析

synchronized是Java 内置的管程方案,synchronized 关键字修饰的代码块和方法在编译期会自动生成相关加锁和解锁的代码。

举个例子, synchronized 分别加在代码块和方法上。

public void methodA() {
    synchronized (this) {
        System.out.println("methodA");
    }
}

synchronized static void methodB() {
    System.out.println("methodB");
}

javap -v 反编译来看。

public void methodA();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: aload_0
         1: dup
         2: astore_1
         3: monitorenter
         4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         7: ldc           #3                  // String methodA
         9: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        12: aload_1
        13: monitorexit                       // 正常退出
        14: goto          22
        17: astore_2
        18: aload_1
        19: monitorexit                       // 异常退出 
        20: aload_2
        21: athrow
        22: return
        ...
            
static synchronized void methodB();
    descriptor: ()V
    flags: (0x0028) ACC_STATIC, ACC_SYNCHRONIZED //同步方法标记
    Code:
      stack=2, locals=0, args_size=0
         0: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #5                  // String methodB
         5: invokevirtual #4                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
         ...
  1. 同步代码块是使用 monitorenter 和 monitorexit 指令实现。

    methodA经反编译后的第3、13、19行指令分别对应的是 monitorenter 和 两个monitorexit指令。其中monitorexit 被插入到方法正常结束处和异常处两个地方,这样可以保证抛异常的情况下也能释放锁。

    同步代码块开始执行时,执行 monitorenter 的线程会尝试获得 monitor 的所有权。如果该 monitor 的计数为 0,则线程获得该 monitor 并将其计数置为 1,该线程就是这个 monitor 的所有者。 如果线程已经拥有了这个 monitor ,则可以重入这个锁,且累加计数。 如果其他线程已经拥有了这个 monitor,那个这个线程就会被阻塞,直到这个 monitor 被释放它的计数为 0,这个线程就会再次尝试获取这个 monitor。

    monitorexit 的作用是将 monitor 的计数器减 1,当减为 0 时代表这个 monitor 被释放,其他正在等待这个 monitor 的线程就可以再次尝试获取这个 monitor 的所有权。

  2. 同步方法是通过ACC_SYNCHRONIZED 标记实现。

    被 synchronized 修饰的方法会有一个 ACC_SYNCHRONIZED 标志。当线程要访问该方法的时候,首先检查方法是否有 ACC_SYNCHRONIZED 标志,如果有则需要先获得 monitor 锁,然后才能开始执行方法,方法执行之后再释放 monitor 锁。如果这时其他线程来请求该方法,会因为无法获得 monitor 锁而被阻塞。

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值