简介
公平锁与非公平锁
1 | Lock lock=new ReentrantLock(true);//公平锁 |
- 公平锁指的是线程获取锁的顺序是按照加锁顺序来的,而非公平锁指的是抢锁机制,先lock的线程不一定先获得锁,效率更高。
- 公平锁每次获取到锁为同步队列中的第一个节点,保证请求资源时间上的绝对顺序,而非公平锁有可能刚释放锁的线程下次继续获取该锁,则有可能导致其他线程永远无法获取到锁,造成“饥饿”现象。
- 公平锁为了保证时间上的绝对顺序,需要频繁的上下文切换,而非公平锁会降低一定的上下文切换,降低性能开销。因此,ReentrantLock默认选择的是非公平锁,则是为了减少一部分上下文切换,保证了系统更大的吞吐量。
Condition类
Lock类可以创建Condition对象,Condition对象用来是线程等待和唤醒线程
一个condition对象的signal(signalAll)方法和该对象的await方法是一一对应的,也就是一个condition对象的signal(signalAll)方法不能唤醒其他condition对象的await方法。
1 | public class MyService { |
- Condition类的awiat方法和Object类的wait方法等效
- Condition类的signal方法和Object类的notify方法等效
- Condition类的signalAll方法和Object类的notifyAll方法等效
底层原理
ReentrantLock先通过CAS尝试获取锁,
如果此时锁已经被占用,该线程加入AQS队列并wait()
当前驱线程的锁被释放,挂在CLH队列为首的线程就会被notify(),然后继续CAS尝试获取锁,此时:
- 非公平锁,如果有其他线程尝试lock(),有可能被其他刚好申请锁的线程抢占。
- 公平锁,只有在CLH队列头的线程才可以获取锁,新来的线程只能插入到队尾。
lock()函数
1 | final void lock() { //非公平锁 |
- 如果成功通过CAS修改了state,指定当前线程为该锁的独占线程,标志自己成功获取锁。
- 如果CAS失败的话,调用acquire();
- acquire()中调用tryAcquire(),会尝试再次通过CAS修改state为1
- 如果失败而且发现锁是被当前线程占用的,就执行重入(state++)
- 如果锁是被其他线程占有,那么当前线程执行tryAcquire返回失败,并且执行addWaiter()进入等待队列,并挂起自己interrupt()
Unlock()函数
- 释放时候,state–,通过state==0判断锁是否完全被释放。
- 成功释放锁的话,唤起一个被挂起的线程
版权声明:本文为博主原创文章,欢迎转载,转载请注明作者、原文超链接,感谢各位看官!!!
本文出自:monkeyGeek
座右铭:生于忧患,死于安乐
欢迎志同道合的朋友一起交流、探讨!
