公平锁与非公平锁

9天前

ReentrantLock有公平锁与非公平锁两种实现,默认为非公平锁,二者的区别在于获取锁的行为有所不同:

  • 非公平锁:调用lock方法时,只要锁是未被占用的状态,就尝试获取,此时如果获取成功且队列中有线程在等待锁,就会造成“插队”
  • 公平锁:调用lock方法时,如果锁是未被占用的状态,先检查队列中当前线程的前面是否有线程在排队,如果有则此线程进队列排队(说明前面这些线程等待的时间比当前线程更长),如果没有则直接尝试获取锁
  1. protected final boolean tryAcquire(int acquires) {
  2. final Thread current = Thread.currentThread();
  3. int c = getState();
  4. if (c == 0) {
  5. if (!hasQueuedPredecessors() &&
  6. compareAndSetState(0, acquires)) {
  7. setExclusiveOwnerThread(current);
  8. return true;
  9. }
  10. }
  11. else if (current == getExclusiveOwnerThread()) {
  12. int nextc = c + acquires;
  13. if (nextc < 0)
  14. throw new Error("Maximum lock count exceeded");
  15. setState(nextc);
  16. return true;
  17. }
  18. return false;
  19. }

这是ReentrantLock.FairSync中的代码,可以看到,当锁未被占用时,在尝试修改状态之前,先调用hasQueuedPredecessors()方法来判断前面是否有线程在排队,如果没有再继续尝试修改状态

  1. public final boolean hasQueuedPredecessors() {
  2. // The correctness of this depends on head being initialized
  3. // before tail and on head.next being accurate if the current
  4. // thread is first in queue.
  5. Node t = tail; // Read fields in reverse initialization order
  6. Node h = head;
  7. Node s;
  8. return h != t && // 队列不为空
  9. ((s = h.next) == null || s.thread != Thread.currentThread());
  10. // 可能有线程正在入队 // 当前线程不是队列中排在队首的线程(head.next)
  11. }

  1. final boolean nonfairTryAcquire(int acquires) {
  2. final Thread current = Thread.currentThread();
  3. int c = getState();
  4. if (c == 0) {
  5. if (compareAndSetState(0, acquires)) {
  6. setExclusiveOwnerThread(current);
  7. return true;
  8. }
  9. }
  10. else if (current == getExclusiveOwnerThread()) {
  11. int nextc = c + acquires;
  12. if (nextc < 0) // overflow
  13. throw new Error("Maximum lock count exceeded");
  14. setState(nextc);
  15. return true;
  16. }
  17. return false;
  18. }

非公平锁的代码,当锁未被占用时,直接尝试修改状态。


0
3
0

添加评论

正在回复:
取消
0
0
3
0