我们知道多线程争抢临界资源,首先先进入entryList队列,然后去争抢实例对象对应的监视器的锁,例如下图ObjectMonitor结构。
waitSet是监视器上等待的线程集合。自己获得锁之后调用wait()方法。
EntryList是阻塞线程集合。ObjectWaiter是链表结构。
(1)wait源码解析
void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) { Thread * const Self = THREAD ;// 将当前线程赋值给Selft /*************/ } |
(2)notify源码解析
void ObjectMonitor::notify(TRAPS) { CHECK_OWNER(); if (_WaitSet == NULL) { //若waitSet为空,直接返回 TEVENT (Empty-Notify) ; return ; } ObjectWaiter * iterator = DequeueWaiter() ; if (iterator != NULL) { /*******/ } else if( Policy == 1){ /*******/
} } } |
结合Object的notify javaDoc,我们知道若一个线程在等待,那么他们中的一个将被唤醒,选择策略在实现上是任意的。在源码中对应各种Policy
(3)notifyAll源码解析
nofifyAll会唤醒ObjectWaiter列表所有对象
void ObjectMonitor::notifyAll(TRAPS) { ObjectWaiter* iterator; if (_WaitSet == NULL) { TEVENT (Empty-NotifyAll) ; return ; }
} } |
(4)synchronized锁
从Jdk1.6开始, synchronized锁d的实现发生了很大变化,jvm引入了相应的优化手段提升性能。这种提升涉及到偏向锁,轻量级锁,重量级锁等从而避免锁的竞争带来的用户态和内核态的切换。锁的优化是由java对象头的中的标志位来实现的,锁的访问与改变都和java对象头息息相关。
从jdk1.6之后,对象实例在堆中化分3个组成部分:对象头,实例数据,对齐填充。对象头组要有3块组成:(1)Mark word (2)指向类的指针(3)数组长度
Mark word它记录了对象,锁以及垃圾回收相关信息,(1)无锁标记(2)偏向锁(3)轻量级锁(4)重量级锁(5)GC标记。
锁的演化由经历: 无锁 ==>偏向锁 ==>轻量级锁 ==>重量级锁
锁的升级是根据偏向锁标志位是否和Mark Word中锁标志位一致来达成的。