synchronized底层原理
点击上方蓝色字体,选择“标星公众号”
优质文章,第一时间送达
作者 | zwy2021
来源 | urlify.cn/UZFj6b
通过反编译class文件,可以看到synchronized最关键的部分是monitor对象。
又因为synchronized关键字使用的方法不同,可以将monitor对象使用分为以下两种情况。
synchronized放在方法签名上
public synchronized void method(){
}
这时候在反编译文件里,该方法的ACC_SYNCHRONIZED访问标志位会被标记
synchronized作为对象锁
public void method(){
synchronized(new Object()){
}
}
这时候ACC_SYNCHRONIZED并不会被标记,但是会执行monitorenter和monitorexit命令,从而实现同步。
可以看到虽然只有一个monitorenter但是有两个monitorexit,这是因为有两种情况可以让当前线程放弃锁,即
当前synchronized代码块运行完
发生中断
monitor对象
其实以上两种方法都是相同的,ACC_SYNCHRONIZED标志位是隐式调用了monitor对象而已。下面来说一下monitor对象以及它是如何实现运作的。
monitor的数据结构
关于存储的monitor对象有以下三种可能,对应不同的synchronzied使用方式,
synchronzied修饰普通方法——>锁的是this,也就是调用当前方法的实例对象
synchronized修饰代码块——>锁的是synchronized后面括号里的方法
synchronized修饰static方法——>锁的是类的.class对象
关于面试的时候会问的各种情况下会不会同步执行,牢记一点
锁的对象相同才会同步执行
锁的对象相同才会同步执行
锁的对象相同才会同步执行
也就是说,类锁对普通方法锁是不存在覆盖的,下面两个方法不会同步执行
public synchronized void method1(){
}
public static synchronized void method2(){
}
monitor运行机制
如果一个线程运行到一个同步代码块,如果线程进入数为0,则该线程可拥有此monitor对象的锁,遇到monitorenter,进入数+1,遇到monitorexit,进入数-1。
如果目前线程进入数不为0,则当前线程不能获得此monitor对象的锁,需要等待。
synchronized的可重入性,不可中断性是如何保障的呢?
monitor对象的线程进入数不是0和1,如果发生重入,进入数+1即可。
不可中断性:一个线程获取锁后,其他线程必须阻塞或等待,不能抢占,按照上面的运行机制,必须线程进入数=0其他线程才能获得锁,因而,不可中断性实现。
另外,有的面试题会问非同步方法和同步方法同时调用会不会同步执行,答案是不会。
因为,非同步方法执行时不会去考虑线程进入数以及获得锁一系列流程,直接开始执行,怎么可能同步执行呢