读线程与读线程之间不互斥
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
ReentrantReadWriteLock实现了这个接口
ReentrantReadWriteLock的使用方法
ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
Lock readLock = readWriteLock.readLock();
readLock.lock();
readLock.unlock();
Lock writeLock = readWriteLock.writeLock();
writeLock.lock();
writeLock.unlock();
ReentrantReadWriteLock的实现
构造方法
public ReentrantReadWriteLock() {
//是否公平
this(false);
}
public ReentrantReadWriteLock(boolean fair) {
//使用公平或者非公平的sync
sync = fair ? new FairSync() : new NonfairSync();
//readerLock 和writerLock 使用同一个sync
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
读写锁和互斥锁一样也是用state来表示锁的状态的,只是操作方式不同
abstract static class Sync extends AbstractQueuedSynchronizer {
//...
static final int SHARED_SHIFT = 16;
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
//int的长度是32位,这里会把state作为参数传入,然后取state的高16位
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
//取state的低16位
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
//...
}
ReentrantReadWriteLock会把state变量拆成两半,低16位,用来记录写锁。如果低16位的值等于5,表示一个写线程重入了5次。高16位,用来记录读锁。例如,高16位的值等于5,既可以表示5个读线程都拿到了该锁;也可以表示一个读线程重入了5次
当state=0时,说明既没有线程持有读锁,也没有线程持有写锁;当state != 0时,要么有线程持有读锁,要么有线程持有写锁,两者不能同时成立,因为读和写互斥。这时再进一步通过sharedCount(state)和exclusiveCount(state)判断到底是读线程还是写线程持有了该锁。
ReentrantReadWriteLock的两个内部类ReadLock和WriteLock中使用state变量
public static class ReadLock implements Lock, java.io.Serializable {
private final Sync sync;
protected ReadLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
public void lock() {
sync.acquireShared(1);
}
public void unlock() {
sync.releaseShared(1);
}
}
public static class WriteLock implements Lock, java.io.Serializable {
private final Sync sync;
protected WriteLock(ReentrantReadWriteLock lock) {
sync = lock.sync;
}
public void lock() {
sync.acquire(1);
}
public void unlock() {
sync.release(1);
}
}
acquire/release、acquireShared/releaseShared 是AQS里面的两对模板方法。
public final void acquireShared(int arg) {
//由AQS的子类sync实现
if (tryAcquireShared(arg) < 0)
//获得锁失败把自己加入等待获取锁队列,阻塞线程等待唤醒
doAcquireShared(arg);
}
public final boolean releaseShared(int arg) {
//由AQS的子类sync实现
if (tryReleaseShared(arg)) {
//唤醒挂起的线程
doReleaseShared();
return true;
}
return false;
}
public final void acquire(int arg) {
//由AQS的子类sync实现
if (!tryAcquire(arg) &&
//获得写锁失败把自己加入阻塞队列
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//响应中断
selfInterrupt();
}
public final boolean release(int arg) {
//由AQS的子类sync实现
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
//唤醒线程
unparkSuccessor(h);
return true;
}
return false;
}
ReentrantReadWriteLock中的sync
//非公平的sync
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
//写线程是否应该阻塞
final boolean writerShouldBlock() {
//非公平锁不阻塞
return false;
}
//读线程是否应该阻塞
final boolean readerShouldBlock() {
//队列中第一个是写线程则阻塞
return apparentlyFirstQueuedIsExclusive();
}
}
//公平的sync
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
//写线程是否应该阻塞
final boolean writerShouldBlock() {
//如果队列中已经有线程在排队则阻塞
return hasQueuedPredecessors();
}
//读线程是否应该阻塞
final boolean readerShouldBlock() {
return hasQueuedPredecessors();
}
}
写锁的实现
public boolean tryLock( ) {
return sync.tryWriteLock();
}
final boolean tryWriteLock() {
Thread current = Thread.currentThread();
//获得state
int c = getState();
//当state不等于0的时候说明有线程获取了锁
if (c != 0) {
//获得写线程的数量
int w = exclusiveCount(c);
//如果写线程==0说明持有锁的是读线程,或者当前线程不是排它锁的持有线程
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
}
//cas将state+1重入
if (!compareAndSetState(c, c + 1))
return false;
//设置排它锁的持有线程为当前线程
setExclusiveOwnerThread(current);
return true;
}
//lock的时候调用tryAcquire,这里是fair的sync
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//前面没有其他线程
if (!hasQueuedPredecessors() &&
//cas设置state为acquires
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;
}
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
//唤醒队列里面的第一个线程
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
读锁的实现
public boolean tryLock() {
return sync.tryReadLock();
}
final boolean tryReadLock() {
Thread current = Thread.currentThread();
for (;;) {
int c = getState();
//如果排它锁的持有线程是写线程,并且当前线程不是持有锁线程
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return false;
//获得读锁的state
int r = sharedCount(c);
if (r == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//cas设置读锁
if (compareAndSetState(c, c + SHARED_UNIT)) {
//如果r=0说明当前线程是第一个读线程
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
//第一个读线程是当前线程
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
// 如果firstReader不是当前线程,则从ThreadLocal中获取当前线程的读锁个数,并设置当前线程持有的读锁个数
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;
}
}
}
public void lock() {
sync.acquireShared(1);
}
public final void acquireShared(int arg) {
if (tryAcquireShared(arg) < 0)
//获取锁失败,将当前线程加入阻塞队列
doAcquireShared(arg);
}
public void unlock() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
//cas设置读线程的state
if (tryReleaseShared(arg)) {
//唤醒线程
doReleaseShared();
return true;
}
return false;
}