synchronized 底层使用的JVM级别中的Monitor 来决定当前线程是否获得了锁,synchronized 属于悲观锁。synchronized 因为需要依赖于JVM级别的Monitor ,相对性能也比较低。
Monitor
monitor对象存在于每个Java对象的对象头中,也是为什么Java中任意对象可以作为锁的原因, monitor内部维护了三个变量:
WaitSet:保存处于Waiting状态的线程
EntryList:保存处于Blocked状态的线程
Owner:持有锁的线程
只有一个线程获取到的标志就是在monitor中设置成功了Owner,一个 monitor中只能有一个Owner。 在上锁的过程中,如果有其他线程也来抢锁,则进入EntryList 进行阻塞,当获得锁的线程执行完了,释放了锁,就会唤醒EntryList 中等待的线程竞争锁,竞争的时候是非公平的。
synchronized 的锁升级的情况
Java中的synchronized有偏向锁、轻量级锁、重量级锁三种形式,分别对应了锁只被一个线程持有、不同线程交替持有锁、多线程竞争锁三种情况。 重量级锁:底层使用的Monitor实现,里面涉及到了用户态和内核态的切换、进程的上下文切换,成本较高,性能比较低。
轻量级锁:线程加锁的时间是错开的(也就是没有竞争),可以使用轻量级 锁来优化。轻量级修改了对象头的锁标志,相对重量级锁性能提升很多。每次修改都是CAS操作,保证原子性
偏向锁:一段很长的时间内都只被一个线程使用锁,可以使用了偏向锁,在第一次获得锁时,会有一个CAS操作,之后该线程再获取锁,只需要判断 mark word中是否是自己的线程id即可,而不是开销相对较大的CAS命令 一旦锁发生了竞争,都会升级为重量级锁