天天看点

ReentrantReadWriteLock源码与锁升降级详解

//读写锁
	private ReadWriteLock lock  =new ReentrantReadWriteLock();
	//读锁  ————共享锁
	private Lock readLock = lock.readLock();
	//写锁  ————排它锁
	private Lock writeLock =lock.writeLock();
           

ReentrantReadWriteLock类实现 ReadWriteLock接口,其中ReadLock类和WriteLock类都实现了Lock接口,都是ReentrantReadWriteLock的静态内部类。

其有一个成员属性为    final Sync sync;

在创建ReentrantReadWriteLock时创建的Sync同步器

查看源码可见,使用了this关键字,默认使用的是不公平锁。

public ReentrantReadWriteLock() {
        this(false);
    }
           
/**
*支持公平锁和不公平锁
*/
public ReentrantReadWriteLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
        readerLock = new ReadLock(this);
        writerLock = new WriteLock(this);
    }
           

继承关系

---->AQS

      ----> Sync

             ---->FairSync

             ---->NonfairSync

ReadLock和WriteLock的lock()方法对比 

//ReadLock的lock()方法,由于读锁是共享锁,使用的是共享模式
 public void lock() {
            sync.acquireShared(1);
        }
           
//WriteLock中使用独享模式,是排它锁
public void lock() {
            sync.acquire(1);
        }
           

读写锁需要保存的状态:

1、写锁重入的次数

2、读锁的个数(写锁是排它锁只有一个)

3、每个读锁的重入次数

如何保存? 由于AQS类的设计目标是成为依靠单个原子 int 值来表示状态的大多数同步器的一个有用基础,int占4个字节,32位,可以分别用16位表示读锁写锁。          

写锁tryAcquire源码

//写锁WriteLock的tryAcquire()方法
protected final boolean tryAcquire(int acquires) {
            //获取当前线程current
            Thread current = Thread.currentThread();
            //获取状态int值
            int c = getState();
//The lower one representing the exclusive (writer) lock hold count,and the upper the shared (reader) hold count.(低位存读锁个数,高位存写锁个数)
            //w为写锁重入次数
            int w = exclusiveCount(c);
            //若c不为0,则是重入锁
            if (c != 0) {
                // (Note: if c != 0 and w == 0 then shared count != 0)
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
         //写锁重入次数+1>最大值(1 << 16 - 1 即 1左移16位减一为65535,写锁支持重入次数)
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // 重入成功,状态值+1,返回true
                setState(c + acquires);
                return true;
            }
            /**查看NonfairSync源码writerShouldBlock永远为false
            *
            * final boolean writerShouldBlock() {
            *    return false; // writers can always barge
            *    }
            */
            //acquires实际上是1
            if (writerShouldBlock() ||
                !compareAndSetState(c, c + acquires))
            //设置c不成功返回false
                return false;
           //设置c成功,把持锁线程设置为当前线程,返回true
            setExclusiveOwnerThread(current);
            return true;
        }
           

写锁tryRelease源码

protected final boolean tryRelease(int releases) {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            int nextc = getState() - releases;
            boolean free = exclusiveCount(nextc) == 0;
            if (free)
                setExclusiveOwnerThread(null);
            setState(nextc);
            return free;
        }
           

读锁tryAcquireShared源码

//当有读线程时,执行tryAcquireShared返回true,当有写线程时,执行tryAcquireShared返回false
//记录读锁重入次数
protected final int tryAcquireShared(int unused) {
            Thread current = Thread.currentThread();
            int c = getState();
            //独占锁不为0(存在写线程) 且 独占线程不是当前线程 返回-1(取不到)
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                return -1;
            int r = sharedCount(c);
            //无读阻塞 且 小于最大值 且设置成功
            if (!readerShouldBlock() &&
                r < MAX_COUNT &&
                compareAndSetState(c, c + SHARED_UNIT)) {
                //r=0表示第一个线程
                if (r == 0) {
                    firstReader = current;
                    firstReaderHoldCount = 1;
                } 
                //当前线程重入,int值自增    
                else if (firstReader == current) {
                    firstReaderHoldCount++;
                } 
                //有另外线程进入竞争
                else {
                    //HoldCounter类记录了重入次数和线程id
                    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 1;
            }
            //使用for(;;)死循环重复执行上述代码,直到返回-1或1结果
            return fullTryAcquireShared(current);
        }
           

读锁WriteLock的tryReleaseShared源码

//读锁WriteLock的tryReleaseShared()
 protected final boolean tryReleaseShared(int unused) {
            Thread current = Thread.currentThread();
            //第一个读锁线程等于当前线程
            if (firstReader == current) {
                // assert firstReaderHoldCount > 0;
                if (firstReaderHoldCount == 1)
                    firstReader = null;
                else
                    firstReaderHoldCount--;
            } else {
                HoldCounter rh = cachedHoldCounter;
                if (rh == null || rh.tid != getThreadId(current))
                    rh = readHolds.get();
                int count = rh.count;
                if (count <= 1) {
                    readHolds.remove();
                    if (count <= 0)
                        throw unmatchedUnlockException();
                }
                --rh.count;
            }
            for (;;) {
                int c = getState();
                int nextc = c - SHARED_UNIT;
                if (compareAndSetState(c, nextc))
                    // Releasing the read lock has no effect on readers,
                    // but it may allow waiting writers to proceed if
                    // both read and write locks are now free.
                    return nextc == 0;
            }
        }
           

锁降级

  • 锁降级就是把写锁降级为读锁
  • 在写锁没有释放的时候,获取到读锁,再释放写锁
private Map<String,Object> map = new HashMap<String,Object>();
	//读写锁
	private ReadWriteLock lock  =new ReentrantReadWriteLock();
	//读锁
	private Lock readLock = lock.readLock();
	//写锁
	private Lock writeLock =lock.writeLock();
	
	private volatile boolean flag;
	
	public void readwrite() {
		//为了保证flag能拿到最新的值 
		readLock.lock();
		if(flag) {
			//对值进行写操作,因为读写锁互斥,若不释放读锁,则写锁无法获取
			readLock.unlock();
			//获取写锁     读锁释放完毕后,所有写锁竞争线程
			writeLock.lock(); 
			//写锁是排它锁,最终有一个线程获得写锁,并执行put写操作
			map.put("hello", "hi");
			//在写完后,若不加读锁,则直接释放读锁,其他线程可能同样进行put()写操作
			//在此加了读锁后,读写锁是互斥的,其他线程必须等待readLock读锁释放后才能写(put )成功
			readLock.lock();   //获取读锁进行锁降级
			//释放写锁
			writeLock.unlock();
		}
		Object value = map.get("hello");
		System.out.println(value);
		readLock.unlock();
	}
           

锁升级

  • 锁升级就是把读锁升级为写锁
  • 在读锁没有释放的时候,获取到写锁,再释放读锁

继续阅读