ReentrantLock解析及源码分析 (2)

公平锁提供了一种绝对等待时间公平的机制,锁永远会被同步等待队列中等待时间最长的获取到,
这样可以保证每个在等待的线程在程序不退出的情况下都可以获取到锁。
但是每一个请求的锁的线程都将进入到同步等待队列中阻塞休眠,线程的休眠和唤醒需要耗费额外的时间,会降低效率,降低吞吐量
(整个在同步等待队列中阻塞休眠的操作不是绝对的,只有所没有被占有,并且同步等待队列为空时可以直接获取锁或者递归调用同一个线程获取锁)

公平锁的同步器 /** * Sync object for fair locks */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { //调用AQS提供的请求加锁的方法 //紧接着下一个代码片段解释 acquire(1); } /** * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. */ //公平版本的tryAcquire, //第一个获取锁的线程和已经获取锁的线程递归调用获取锁不需要再排队等待 protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { //判断同步等待队列中是否有其他等待获取锁的线程 //没有并且锁没有被其他线程持有则可以直接获取锁 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } //如果当前线程持有锁,则可以锁计数器加一让该线程再一次获取锁 else if (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } //否则当前线程在这次尝试获取锁之前就没有获取到锁 //同步等待队列中有其他线程在尝试获取锁 //则获取锁失败,下一步应该会被加入到同步等待队列 return false; } }

简单看下hasQueuedPredecessors()方法,这里只解释满足公平锁加锁条件的情况

/** * Queries whether any threads have been waiting to acquire longer * than the current thread. */ //这个方法是再AQS中提供的用来判断线同步等待队列中是否还有等待时间比当前线程等待时间更长的线程 //tail是队列的尾节点,head是头节点,每个节点会代表一个线程首尾节点除外 //再tryAcquire中我们希望它返回的时false那么看下返回false代表那种情况 //返回false要求 h != t && ((s = h.next) == null|| s.thread != Thread.currentThread())为false,那么要么h==t就是头尾节点是同一个,队列为空 //要么(s = h.next) == null|| s.thread != Thread.currentThread()为false, //这就要求h.next!=null 并且h.next就是当前线程,也就是说队列中第一个等待获取锁的线程就是当前线程 //那么就可以直接加锁; public final boolean hasQueuedPredecessors() { // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); } 公平锁的加锁

在公平锁的同步器中提供了lock()方法用来进行加锁操作,
可重入锁进行加锁的方法也确实是调用同步器的lock()来实现加锁

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyjsjx.html