java中的每个对象都会带有锁,锁是存在于java对象内部的数据结构,每一个对象中的锁都与一个monitor(监视器相关联)
当一个线程访问同步区域时,首先会请求对象的monitor,在monitor以下几种状态来区分线程:
Contention List:所有请求锁的线程将被首先放置到该竞争队列。
Entry List:Contention List中那些有资格成为候选人的线程被移到Entry List。
Wait Set:那些调用wait方法被阻塞的线程被放置到Wait Set。
OnDeck:任何时刻最多只能有一个线程正在竞争锁,该线程称为OnDeck,可以理解为Ready线程
Owner:获得锁的线程称为Owner。
!Owner:释放锁的线程。
monitor还拥有以下结构:
Nest:用来实现重入锁的计数。
HashCode:保存从对象头拷贝过来的HashCode值(可能还包含GC age)。
Candidate:用来避免不必要的阻塞或等待线程唤醒,因为每一次只有一个线程能够成功拥有锁,如果每次前一个释放锁的线程唤醒所有正在阻塞或等待的线程,会引起不必要的上下文切换(从阻塞到就绪然后因为竞争锁失败又被阻塞)从而导致性能严重下降。Candidate只有两种可能的值0表示没有需要唤醒的线程1表示要唤醒一个继任线程来竞争锁。
线程进入synchronize块之前会获取锁,无论是通过正常路径退出还是抛出异常,线程都会在失去对synchronized代码块的控制时自动释放锁。