Synchronized的基本知识、实现原理以及其与ReentrantLock的区别
加了synchronized的方法看class文件会多下面三个
Monitorenter
Monitorexit
monitorexit
为什么有两个退出,抛出异常时候也要monitorexit,不然报出异常锁不能释放。
synchronized为什么要传入一个对象参数?
每一个对象都有一个对应的对象监视器Monitor
对象监视器
ObjectMonitor{
_owner = null;当前获得锁的线程
_waitSet=null;等待队列(o.wait())
_cxq = null;
_EntryList=null;同步队列
…
}
对象的头信息可以记录获取到的线程Id,每个对象拥有的Monitor可以存储那个线程获取了该锁(对象),同时也可以记录等待的线程和同步的线程,这样就可以通过逻辑判断保证同一时刻只有一个线程能获得锁。
简单逻辑描述:
无锁状态时没有线程来,
偏向锁时有线程来了,但是只有一个,对象头记录一下你这个线程id就行了,下次你再来直接用。
轻量级锁,当两个及两个以上线程来了(但不是很多)发生争抢,CAS(比较合适替换),只有一个线程能抢到锁,其他线程死循环阻塞等待,当使用的线程释放锁之后其余的争抢,可以看出是不公平的锁。由于没有去向系统内核申请资源,自己就解决了,没有用户态和内核态的切换,所以效率比重量级锁高。但是争抢线程数不能太多,同时获得锁的线程执行时间不能过长(等待的其他线程自旋次数过多),有这任何一点轻量级锁的效率就不如重量级锁了,所以会升级为重量级锁。
重量级锁,ObjectMonitor的_owner标识那个线程抢到了锁,其余的放入队列_EntryList同步队列中等待。
抢到锁的线程调用o.wait()后会释放锁同时线程进入_waitSet等待队列,当调用notify()方法后才会从等待队列进入到同步队列。
当抢到线程的锁释放后,同步队列的线程再去争抢到锁,也可以看出是不公平的锁。
当然synchronized还有许多细节判断操作,这里只简单描述了下主要的。
Lock和synchronized比较详解
Java锁–Lock实现原理(底层实现)