题记
讲讲写这篇博客的原因,因为自认为对synchronized这个关键字很了解了,前几天和一个刚好在找工作的朋友聊到了这个。结果他把面试遇到的一个问题给我出了出来,当我蒙圈的那一刻才懂得自己之前的了解只是皮毛。
正文
对于synchronized这个关键字,只要是学过java的我们对它都不陌生,而且感觉还非常熟悉。那我们就先来说一说面试和实际使用当中会遇到的两个场景。
- 场景1:
public class SynchronizedTest {
public synchronized static int getGender(){
return 1;
}
public synchronized int getAge(){
return 25;
}
}
当同时调用这两个方法的时候会不会阻塞?根据锁的门栓的不同,静态方法锁的是类的字节码文件,而实例方法锁的是调用方法的实例对象。所以同时调用两个方法并不会阻塞!
- 场景2:
public class SynchronizedTest {
public synchronized int getGender() {
return 1;
}
public synchronized int getAge() {
return 25;
}
public String getName() {
return "测试";
}
}
这种情况当同时调用三个方法的时候会不会阻塞,由场景1的经验知道,前两个锁的对象是一样的,所以前两个方法之间会阻塞,第三个方法则不受影响。
- 场景3:终极场景
public class SynchronizedTest {
public synchronized int getGender() {
return 1;
}
public int getAge() {
int i = 0;
synchronized (this) {
i++;
return i;
}
}
}
当同时调用这两个方法的时候会不会阻塞?重点内容随着查阅资料和对synchronized 的实现的深入了解,知道synchronized 修饰实例方法和修饰代码块的synchronized(this)的内部实现是不一样的,所以它们锁的门栓并不是一样的。修饰在实例方法上时它是基于常量池里面的ACC_SYNCHRONIZED这个标识来实现的同步锁机制,而修饰代码块的这种synchronized(this)方式是基于对象存储的时候的头对象中的Mark Word里面的信息来实现的。
于2018-08-11特意来道歉,上面的描述不够准确,经过自测,虽然synchronized修饰代码块和修饰方法通过用javap -c
命令反编译的汇编来看是不一样的,但是他们还是获得的一样的锁,一样会互斥阻塞。反编译参考下面文章
https://www.cnblogs.com/huangyin/p/6586469.html
感想
后续还要持续研究,继续深入了解java相关的深入实现~
另外附上对此理解更深刻,研究比较透彻的几篇文章
深入理解Java并发之synchronized实现原理
synchronized在JVM底层的实现原理及Java多线程锁理解
Java并发编程:Synchronized及其实现原理