本文共 2708 字,大约阅读时间需要 9 分钟。
ReentrantReadWriteLock是一把可重入读写锁,提高了读的性能。读写锁时如何实现了呢。
其实读写锁还是通过一个compareAndSet实现的,只是里面的state的含义不一样了,原先是表示线程的重入次数,现在对该变量做了拆分。高16位表示读线程的重入次数,第16位表示写线程的重入次数。
下面我们看几个变量和方法
static final int SHARED_SHIFT = 16; //1 0000 0000 0000 0000 用于读线程重入一次 static final int SHARED_UNIT = (1 << SHARED_SHIFT); //读线程最大重入次数 static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; //FFFF FFFF FFFF FFFF 用于计算写线程重入次数 static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; //获取读线程重入次数 static int sharedCount(int c) { return c >>> SHARED_SHIFT; } //获取写线程重入次数 static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
获取写锁
final boolean tryWriteLock() { Thread current = Thread.currentThread(); int c = getState(); //如果c等于0,说明空闲,如果非0,说明已经被占用了 if (c != 0) { //获取写线程重入次数 int w = exclusiveCount(c); //如果当前没有写线程,或者写线程不是当前线程,直接返回失败 if (w == 0 || current != getExclusiveOwnerThread()) return false; //如果写线程已经超过最大重入次数了,则报错 if (w == MAX_COUNT) throw new Error("Maximum lock count exceeded"); } //占用锁 if (!compareAndSetState(c, c + 1)) return false; setExclusiveOwnerThread(current); return true; }
获取读锁
final boolean tryReadLock() { Thread current = Thread.currentThread(); for (;;) { int c = getState(); //如果当前存在写锁,并且不是当前线程,则直接获取锁失败 if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return false; //获取读锁重入次数 int r = sharedCount(c); if (r == MAX_COUNT) throw new Error("Maximum lock count exceeded"); //读锁占用 if (compareAndSetState(c, c + SHARED_UNIT)) { if (r == 0) { firstReader = current; firstReaderHoldCount = 1; } else if (firstReader == current) { firstReaderHoldCount++; } else { HoldCounter rh = cachedHoldCounter; if (rh == null || rh.tid != getThreadId(current)) cachedHoldCounter = rh = readHolds.get(); else if (rh.count == 0) readHolds.set(rh); rh.count++; } return true; } } }
转载地址:http://esjqi.baihongyu.com/