ReentrantReadWritelock

java并发编程之美 笔记

读写锁ReentrantReadWritelock

结构

public class ReentrantReadWriteLock
        implements ReadWriteLock, java.io.Serializable {

   	private final ReentrantReadWriteLock.ReadLock readerLock;
	private final ReentrantReadWriteLock.WriteLock writerLock;
    final Sync sync;


    public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
         //内部维护了一个读锁和写锁
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }

    public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
    public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock; }


    abstract static class Sync extends AbstractQueuedSynchronizer {}

    static final class NonfairSync extends Sync { }

    static final class FairSync extends Sync { }

    //读锁: shared锁
    public static class ReadLock implements Lock, java.io.Serializable {}

    //写锁: exclusive(独占)锁
    public static class WriteLock implements Lock, java.io.Serializable {}
}

Sync
AQS只维护了一个状态state,但是读写锁需要维护读和写两个状态; ReentrantReadWriteLock巧妙的运用了

  • state的高16位表示读状态即可以获取读锁的次数(可以允许多个线程同时持有锁),
    -低16位表示写锁可重入次数;

假设读锁允许重入7次, 写锁允许持有5次,那么state值为
00000000 00000111 00000000 00000101 = 458757

//java.util.concurrent.locks.ReentrantReadWriteLock.Sync
 abstract static class Sync extends AbstractQueuedSynchronizer {

        static final int SHARED_SHIFT   = 16;
    	
    	//即2^16 : 00000000 00000001 00000000 00000000 
    	// shareCount+SHARED_UNIT 组成state的高16位
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);

       //读锁与写锁的最大值都为即2^16 - 1
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;

        //即2^16 - 1 ;  00000000 00000000 11111111 1111111 
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

       
       //使用state高16位表示读锁次数
        static int sharedCount(int c)    { 
        	// 00000000 00000111 00000000 00000101 
        	// 右移动16位为
        	// 00000000 00000000 00000000 00000111 = 7
        	return c >>> SHARED_SHIFT; 
        }

        static int exclusiveCount(int c) { 
        	// 00000000 00000111 00000000 00000101 &  00000000 00000000 11111111 1111111 
        	// c前16位为0,只保留后16位数:
        	// 00000000 00000000 00000000 00000101 = 5
        	return c & EXCLUSIVE_MASK; 
        }

}	
  • 重入
    • 读线程在获取了读锁后还可以获取读锁;
    • 写线程在获取了写锁之后既可以再次获取写锁又可以获取读锁;
  • 锁降级
    • 允许从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。反之,则不允许。

写锁

获取写锁

//java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock
public void lock() {
 //1.调用AQS的方法--内部调用 2.Sync.tηrAcquire()
     sync.acquire(1);
 }

//java.util.concurrent.locks.ReentrantReadWriteLock.Sync
//2.
 protected final boolean tryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState();
    int w = exclusiveCount(c);
    //c != 0 ,表示读锁或者写锁已经被某个线程获取
    if (c != 0) {
        //  w==0 说明有线程获取了读锁,但是没有线程持有写锁, 需要将锁“升级” 不允许,
        //  已有线程持有了写锁,但不是当前线程,不允许.
        if (w == 0 || current != getExclusiveOwnerThread())
            return false;

        //执行到此的逻辑为: w != 0 && current == getExclusiveOwnerThread() 即当前线程持有写锁
       
        if (w + exclusiveCount(acquires) > MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
        
        // 更新state
        setState(c + acquires);
        return true;
    }

    //执行到此逻辑为c == 0; 即第一个持有锁的线程
    
    
    if (writerShouldBlock() || //3. 若返回false,则尝试执行后续cas操作,若为true,则直接返回false;
        !compareAndSetState(c, c + acquires)) //cas更新
        return false;
    setExclusiveOwnerThread(current);
    return true;
}

3.writerShouldBlock()由子类FairSync,NonfairSync实现,它有两种实现逻辑:

  • 非公平锁: 直接返回false,即不阻塞,直接执行后续的cas操作
  • 公平锁: 则需要判断当前线程是否为AQS等待队列中的第一个.
//NonfairSync
final boolean writerShouldBlock() {
    return false; 
 }

//FairSync
final boolean writerShouldBlock() {
    return hasQueuedPredecessors();
}

释放写锁

//java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock
public void unlock() {
	 //1.调用AQS的release()方法--内部调用 2.Sync.tryRelease()
     sync.release(1);
 }

//java.util.concurrent.locks.ReentrantReadWriteLock.Sync
protected final boolean tryRelease(int releases) {
	//getExclusiveOwnerThread() == Thread.currentThread();
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();

    //当一个线程获取写锁时,读锁的状态肯定为0, 所以这里没有考虑state的高16位
    int nextc = getState() - releases;
    boolean free = exclusiveCount(nextc) == 0;
    // 如采写锁可重入值为 0则释放锁,否则 只是简单地更新状态值
    if (free)
        setExclusiveOwnerThread(null);
    setState(nextc);
    return free;
}

读锁

获取读锁

//java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock
public void lock() {
	//1.调用AQS.acquireShared
	sync.acquireShared(1);
}


//java.util.concurrent.locks.AbstractQueuedSynchronizer
public final void acquireShared(int arg) {
	//2.由子类实现Sync
    if (tryAcquireShared(arg) < 0)
        doAcquireShared(arg);
}


//2. java.util.concurrent.locks.ReentrantReadWriteLock.Sync

abstract static class Sync extends AbstractQueuedSynchronizer {

	//记录每个线程持有的read锁个数
	static final class HoldCounter {
        int count = 0;
        final long tid = getThreadId(Thread.currentThread());
    }

   static final class ThreadLocalHoldCounter
        extends ThreadLocal<HoldCounter> {
        public HoldCounter initialValue() {
            return new HoldCounter();
        }
    }

	private transient ThreadLocalHoldCounter readHolds;

	//记录最后一个获取读锁的线程对应的HoldCounter
    private transient HoldCounter cachedHoldCounter;

    //记录第一个持有读锁的线程
    private transient Thread firstReader = null;
    private transient int firstReaderHoldCount;

    //获取共享所入口--STARTER
	protected final int tryAcquireShared(int unused) {
	    Thread current = Thread.currentThread();
	    int c = getState();

	    //写锁被占用 && 占用线程不是当前线程,直接不允许使用读锁;
	    //如果是当前线程占用写锁, 则可以“锁降级”为读锁
	    if (exclusiveCount(c) != 0 &&
	        getExclusiveOwnerThread() != current)
	        return -1;
	   	
	    int r = sharedCount(c);

	    //尝试获取读锁,
	    //readerShouldBlock(): 
	    if (!readerShouldBlock() && //3.
	        r < MAX_COUNT &&
	        compareAndSetState(c, c + SHARED_UNIT)) {// cas操作更新state
	        if (r == 0) {
	        	//第一个获取读锁的线程
	            firstReader = current;
	            firstReaderHoldCount = 1;
	        } else if (firstReader == current) {
	        	//第一个获取读锁的线程----重入
	            firstReaderHoldCount++;
	        } else {
	            HoldCounter rh = cachedHoldCounter;
	            if (rh == null || rh.tid != getThreadId(current))
	            	//从ThreadLocal中获取当前线程对应的HoldCounter,并设置到cachedHoldCounter变量
	                cachedHoldCounter = rh = readHolds.get();
	            else if (rh.count == 0)
	                readHolds.set(rh);

	            //持有读锁++
	            rh.count++;
	        }
	        return 1;
	    }

	    //4. 类似tryAcquireShared,但是是自旋获取
	    return fullTryAcquireShared(current);
	}

}


//3.
//3.1 NonfairSync
 final boolean readerShouldBlock() {
 	//由AQS实现: 判断head.next是否为独占锁,如果是返回true
    return apparentlyFirstQueuedIsExclusive();
}

//3.2 FairSync
final boolean readerShouldBlock() {
	//判断head.next.thread 是否为当前线程,如果不是 返回true
    return hasQueuedPredecessors();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值