首先声明,这个是转贴,转自:https://juejin.im/post/5d5374076fb9a06ac76da894?utm_source=gold_browser_extension,下面是我看过之后自己的总结。
一、What
Synchronized是什么?
Synchronized是JAVA语言中的关键字,他可以用在方法上例如:
也可以用在代码块上,例如:
他的作用是锁,什么意思呢?就是在并发环境下,有且只有一个线程可以进入被Synchronized包裹的地方,保证线程安全。
二、How
Synchronized是怎么实现的呢?
经过反编译发现,添加了synchronized关键字的代码块,多了两个指令monitorenter、monitorexit。即JVM使用monitorenter和monitorexit两个指令实现同步。
添加了synchronized关键字的方法,多了ACC_SYNCHRONIZED标记。即JVM通过在方法访问标识符(flags)中加入ACC_SYNCHRONIZED来实现同步功能。
那么 monitorenter、monitorexit、ACC_SYNCHRONIZED 又是怎么实现锁的呢?
Monitorenter 执行流程
monitorexit 执行流程
ACC_SYNCHRONIZED 是隐式的,也是通过moitor 执行流程
monitor 是一个虚拟机中的对象,他内部有2个列表,_EntryList 和 _WaitSet
举个例子
synchronized(this){ //进入_EntryList队列
doSth();
this.wait(); //进入_WaitSet队列
}
- 想要获取monitor的线程,首先会进入_EntryList队列。
- 当某个线程获取到对象的monitor后,进入_Owner区域,设置为当前线程,同时计数器_count加1。
- 如果线程调用了wait()方法,则会进入_WaitSet队列。它会释放monitor锁,即将_owner赋值为null,_count自减1,进入_WaitSet队列阻塞等待。
- 如果其他线程调用 notify() / notifyAll() ,会唤醒_WaitSet中的某个线程,该线程再次尝试获取monitor锁,成功即进入_Owner区域。
- 同步方法执行完毕了,线程退出临界区,会将monitor的owner设为null,并释放监视锁。
三.Why
为什么这么设计呢,这样设计其实是很大程度上的解耦,每次需要上锁的时候,根据对象头(存到内存中的对象都有对象头)获取monitor对象,然后进行管理就好了,如果是每个对象都有一个是否上锁的标志的话,就会又乱又麻烦。