深入synchronized原理详解

synchronized作用在方法上时,锁住的便是对象实例(this);当作用在静态方法时锁住的便是对象对应的Class实例,因为Class数据存在于永久代,因此静态方法锁相当于该类的一个全局锁;当synchronized作用于某一个对象实例时,锁住的便是对应的代码块。在HotSpot JVM实现中,锁有个专门的名字:对象监视器(monitor)。
synchronized就是针对内存区块申请内存锁,this关键字代表类的一个对象,所以其内存锁是针对相同对象的互斥操作,而static成员属于类专有,其内存空间为该类所有成员共有,这就导致synchronized()对static成员加锁,相当于对类加锁,也就是在该类的所有成员间实现互斥,在同一时间只有一个线程可访问该类的实例 。
下面我们来说说synchronized在JVM中工作过程

public class SynchronizedThis {

    public void methodA(){
        synchronized (this) {
            System.out.println("this A start:"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("this A end:"+Thread.currentThread().getName());
        }
    }

    public synchronized void methodB(){
        System.out.println("this B start:"+Thread.currentThread().getName());
        System.out.println("this B end:"+Thread.currentThread().getName());
    }
}

首先看下synchronized反汇编结果

D:\xiaonuo\abc\src\com\thread>javac SynchronizedThis.java
D:\xiaonuo\abc\src\com\thread>javap -c SynchronizedThis.class
Compiled from "SynchronizedThis.java"
public class com.thread.SynchronizedThis {
  public com.thread.SynchronizedThis();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
  public void methodA();
    Code:
       0: aload_0
       1: dup
       2: astore_1
       3: monitorenter //进入到一个同步线程,这个线程被锁住
       4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
       7: new           #3                  // class java/lang/StringBuilder
      10: dup
      11: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      14: ldc           #5                  // String this A start:
      16: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokestatic  #7                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      22: invokevirtual #8                  // Method java/lang/Thread.getName:()Ljava/lang/String;
      25: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      28: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      31: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      34: ldc2_w        #11                 // long 1000l
      37: invokestatic  #13                 // Method java/lang/Thread.sleep:(J)V
      40: goto          48
      43: astore_2
      44: aload_2
      45: invokevirtual #15                 // Method java/lang/InterruptedException.printStackTrace:()V
      48: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      51: new           #3                  // class java/lang/StringBuilder
      54: dup
      55: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      58: ldc           #16                 // String this A end:
      60: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      63: invokestatic  #7                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      66: invokevirtual #8                  // Method java/lang/Thread.getName:()Ljava/lang/String;
      69: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      72: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      75: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      78: aload_1
      79: monitorexit
      80: goto          88
      83: astore_3
      84: aload_1
      85: monitorexit // 离开线程,释放锁
      86: aload_3
      87: athrow
      88: return
    Exception table:
       from    to  target type
          34    40    43   Class java/lang/InterruptedException
           4    80    83   any
          83    86    83   any
  public synchronized void methodB();
    Code:
       0: getstatic     #2   //  获取指定类的静态域,并将其值压入栈顶   // Field java/lang/System.out:Ljava/io/PrintStream;
       3: new           #3                  // class java/lang/StringBuilder
       6: dup
       7: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      10: ldc           #17                 // String this B start:
      12: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      15: invokestatic  #7                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      18: invokevirtual #8                  // Method java/lang/Thread.getName:()Ljava/lang/String;
      21: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      24: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      27: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      30: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
      33: new           #3                  // class java/lang/StringBuilder
      36: dup
      37: invokespecial #4                  // Method java/lang/StringBuilder."<init>":()V
      40: ldc           #18                 // String this B end:
      42: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      45: invokestatic  #7                  // Method java/lang/Thread.currentThread:()Ljava/lang/Thread;
      48: invokevirtual #8                  // Method java/lang/Thread.getName:()Ljava/lang/String;
      51: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      54: invokevirtual #9                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      57: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      60: return
}

上面全是JVM的一些命令,JVM的具体执行过程我也是一头雾水,欢迎一起探讨学习。
MethodA 是synchronized(this)通过反汇编可以看出是通过monitor来控制线程访问,但是MethodB没有体现出monitor来,有清楚的大牛们可以多多留言指点,谢谢
我通过网上查询资料synchronized方法反汇编之后在常量池中会有ACC_SYNCHRONIZED标示符, JVM就是根据该标示符来实现方法的同步的:当方法调用时,调用指令将会检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor。在方法执行期间,其他任何线程都无法再获得同一个monitor对象。 其实本质上没有区别,只是方法的同步是一种隐式的方式来实现,无需通过字节码来完成(出自http://www.cnblogs.com/paddix/
在JVM中synchronized是通过监视器(monitor)来控制线程的访问,每个对象都会有一个monitor,如果monitor为0,线程可以进入monitor执行,然后monitor置为1,该monitor被该线程持有,如果该线程再次访问可以继续执行,并且monitor累计加1。此时如果其他线程要访问monitor,由于该monitor被上个线程占用,其他线程将被阻塞,知道上个线程运行完毕并且monitor置为0,该线程才能访问。
因此,Synchronized的语义底层是通过一个monitor的对象来完成,其实wait/notify等方法也依赖于monitor对象,这就是为什么只有在同步的块或者方法中才能调用wait/notify等方法,否则会抛出java.lang.IllegalMonitorStateException的异常的原因。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值