我网站关键词太多,广告推广语,河北商城网站搭建多少钱,wordpress禁止缩略图ReentrantLock公平性实现原理
在ReentrantLock类内部定义了一个内部类Sync以及两个实现NonfairSync和FairSync#xff0c;它们内部定义了锁获取和释放的逻辑#xff0c;下面我列出了两种同步类的代码#xff0c;通过观察两个代码的差异就可以看到公平性是如何实现的。 Nonf…ReentrantLock公平性实现原理
在ReentrantLock类内部定义了一个内部类Sync以及两个实现NonfairSync和FairSync它们内部定义了锁获取和释放的逻辑下面我列出了两种同步类的代码通过观察两个代码的差异就可以看到公平性是如何实现的。 NonfairSync和FairSync的差异如下 差异1非公平锁在获取锁时增加一条shortcut尝试快速获取锁 差异2公平锁在尝试获取锁前需保证当前线程位于AQS队列的头部 static final class NonfairSync extends Sync {private static final long serialVersionUID 7316153563782823691L;/*** Performs lock. Try immediate barge, backing up to normal* acquire on failure.*/final void lock() {if (compareAndSetState(0, 1)) // 差异1非公平锁在一开始可以直接尝试获取锁而不需要再经过acquire-tryAcquire-nonfairTryAcquire这样长的路径setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}final boolean nonfairTryAcquire(int acquires) {final Thread current Thread.currentThread();int c getState();if (c 0) {// 差异2非公平锁在获取锁时不需要判断当前线程是否处在队头if (compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current getExclusiveOwnerThread()) {int nextc c acquires;if (nextc 0) // overflowthrow new Error(Maximum lock count exceeded);setState(nextc);return true;}return false;}
}static final class FairSync extends Sync {private static final long serialVersionUID -3000897897090466540L;final void lock() {// 差异1公平锁不能在一开始直接获取锁否则可能先于队列中的等待线程获取到锁破坏了公平性acquire(1);}/*** Fair version of tryAcquire. Dont grant access unless* recursive call or no waiters or is first.*/protected final boolean tryAcquire(int acquires) {final Thread current Thread.currentThread();int c getState();if (c 0) {// 差异2公平锁实现中线程处于队头才有资格获取锁保证了公平性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方法检查当前线程是否在队头只有在队头的线程才能获取到锁这样如果新来一个线程在它入队前是不会拿到锁的从而保证了线程获取锁的顺序 线程申请锁的顺序也就是说实现了公平性。
ReentrantLock公平性测试
在上一节说到了ReentrantLock的公平性如果是公平锁线程获取锁的顺序 线程访问锁的顺序如果是非公平锁线程获取锁的顺序 ≠ 线程访问锁的顺序那也就是说如果使用非公平锁一个还没有被加入到队列的新线程可能会抢走早已在队列中等待的线程的锁。基于这个思路我们来写一个程序来验证ReentrantLock的公平性。 具体步骤如下
主线程获取锁但不释放创建若干打印线程打印字符p并运行这些线程不能拿到锁因而被依次放到队列中等待主线程释放锁同时立即创建几个新打印线程打印字符s运行。
假如是公平锁那么新打印线程必定会入队等待按序获取锁那么最终打印的字符s永远不可能出现在字符p之前但如果是非公平锁新打印线程有机会与旧打印线程同时竞争锁那么这时候字符s可能会出现在字符p之前。 最终的程序如下
import org.junit.jupiter.api.Test;import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;import static org.junit.jupiter.api.Assertions.*;class ReentrantLockTest {Testpublic void test() throws InterruptedException {ReentrantLock lock new ReentrantLock(true);final int threadNum 50;// 主线程先获取锁lock.lock();// 将几个线程在锁队列中排队ListThread threads new ArrayList();for (int i 0; i threadNum; i) {Thread thread new Thread(() - {try {lock.lock();System.out.printf(Thread.currentThread().getName() );} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}, p);thread.start();threads.add(thread);}// 主线程释放锁再创建几个线程竞争锁Thread.sleep(200);lock.unlock();ListThread threads1 new ArrayList();for (int i 0; i threadNum * 2; i) {Thread thread new Thread(() - {try {lock.lock();System.out.printf(Thread.currentThread().getName() );} catch (Exception e) {e.printStackTrace();} finally {lock.unlock();}}, s);thread.start();threads.add(thread);}for (Thread thread : threads) {thread.join();}// 预计successor-number可能输出在number之前}
}
fair为true时输出结果为
p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p p s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s
fair为false时输出结果为
p p p p p s p s s p p s p s s s p p p p p s s p p p s p s p p p s p s p p p s p s p p p s p p p s p p p p p p p s p p p s p s p s s p p s p s p p p s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s s