【线程】ReentrantReadWriteLock 内部共享锁与排他锁源码剖析 (十一)

我的原则:先会用再说,内部慢慢来。
学以致用,根据场景学源码


一、概念

  1. 共享锁(SHARED): 读操作相关的锁。我正在read,任何人都可以 read。
  2. 排他锁(EXCLUSIVE): write 操作相关的锁,我正在write,别人不能write,不能read(避免不同的人读到的信息不一样)

二、ReentrantReadWriteLock 整体架构

在这里插入图片描述

package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
import java.util.Collection;

public class ReentrantReadWriteLock
        implements ReadWriteLock, java.io.Serializable {
    private static final long serialVersionUID = -6992448646407690164L;
    /** 读锁 */
    private final ReentrantReadWriteLock.ReadLock readerLock;
    /** 写锁 */
    private final ReentrantReadWriteLock.WriteLock writerLock;
    
    final Sync sync;

    /** 默认非公平锁 **/
    public ReentrantReadWriteLock() {
        this(false);
    }

    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 {
    	private static final long serialVersionUID = 6317671515068378041L;
    	// 高16位是 read锁,低16位是 write 锁
        static final int SHARED_SHIFT   = 16;
        // read 锁的单位, write在低16位,所以单位是1,read锁在高16位,所以单位是 1 * 2 ^ 16
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
        // read 锁最大的数量
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
        // write 锁最大的数量
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
        // 获取当前共享锁的数量,也就是 read 锁的数量。 直接右移 16 位,剩下的就是 read 锁的数量了
        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
        /*  
         *  
         *  获取当前独占锁的数量,也就是 write 锁的数量 ,抹掉前面16位
         *	二进制运算: n & ( 2 ^ m - 1) == n mod (2 ^ m)
         *  比如: 7  & ( 2 ^ 2 -1 ) = 7 mod (2 ^ 2) = 3 
         *  也就是取余数操作可以用与运算来解决。
         */
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

		// 计数器
        static final class HoldCounter {
        	// 某个读线程重入的次数
            int count = 0;
            // tid表示该线程的tid字段的值
            final long tid = getThreadId(Thread.currentThread());
        }

        // 本地线程计数器
        static final class ThreadLocalHoldCounter
            extends ThreadLocal<HoldCounter> {
            // 重写初始化方法,在没有进行set的情况下,获取的都是该HoldCounter值	
            public HoldCounter initialValue() {
                return new HoldCounter();
            }
        }

        private transient ThreadLocalHoldCounter readHolds;
        private transient HoldCounter cachedHoldCounter;
       
        private transient Thread firstReader = null;
        private transient int firstReaderHoldCount;

        Sync() {
            readHolds = new ThreadLocalHoldCounter();
            setState(getState()); // ensures visibility of readHolds
        }
    }

    static final class NonfairSync extends Sync {}
    static final class FairSync extends Sync {}
    public static class ReadLock implements Lock, java.io.Serializable {}
    public static class WriteLock implements Lock, java.io.Serializable {}
    ...

}
  • 读写状态的设计
    在这里插入图片描述
假设当前同步状态值为S,get和set的操作如下:
(1)获取写状态:
   		 S&0x0000FFFF:将高16位全部抹去

(2)获取读状态:
  	  	S>>>16:无符号补0,右移16位

(3)写状态加1:
    	 S+1

(4)读状态加1:
  S+(1<<16)即S + 0x00010000

在代码层的判断中,如果S不等于0,那么就有两种情况:
1. write 锁被获取:S&0x0000FFFF > 0
2. read 锁被获取:S>>>16 > 0

=== 点击查看top目录 ===

三、lock.readLock().lock() (读)剖析

  • 看下 ReadLock#lock 方法
public void ReentrantReadWriteLock.ReadLock#lock() {
    sync.acquireShared(1);
}
  • 看下 AbstractQueuedSynchronizer#acquireShared 方法
public final void AbstractQueuedSynchronizer#acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
    	// 返回 -1 才走这里,进入队列阻塞等待
        doAcquireShared(arg);
}
  • 看下 ReentrantReadWriteLock.Sync#tryAcquireShared 方法

protected final int ReentrantReadWriteLock.Sync#tryAcquireShared(int unused) {

    Thread current = Thread.currentThread();
    // 当前状态
    int c = getState();
    
    /*
    	画个重点:
    	 1. 如果 write 锁线程数不是0 ,但是如果是当前thread持有锁的话,同样可以去获取读锁。这里成为锁降级。
    	 2. 如果 write 锁线程数不是0, 但是其他 thread 来获取锁的话,直接就返回 -1了
     */	 
    // 如果 write 的独占锁线程数不等于0,并且不是当前thread,那么就返回 -1,表示获取锁失败
    if (exclusiveCount(c) != 0 &&
        getExclusiveOwnerThread() != current)
        return -1;

    // read 锁的数量
    int r = sharedCount(c);
    /* 
     * readerShouldBlock :
     * read 锁是否需要blocking。如是非公平锁 NonfairLock ,那么不用排队直接抢。
     * 如果是公平锁 FairLock,那么就判断下是否线程中有没有sync队列,如果没有,那么不用排队,如果有,判断下是不是重入,是的话,不用排队。
     */
    if (!readerShouldBlock() &&
    	// 看下是否撑爆炸了,read 锁的数量要小于最大数 MAX_COUNT
        r < MAX_COUNT &&
        // 设置一下 read 锁的数量
        compareAndSetState(c, c + SHARED_UNIT)) {

        if (r == 0) { //  1. read 锁数量是0 
            firstReader = current; 
            firstReaderHoldCount = 1; //第一个 reader 拿到了1个 read 锁
        } else if (firstReader == current) { // 2. 第一个 reader 重入
            firstReaderHoldCount++; // read 锁数量 ++
        } else { // 3. read 锁数量不是0,而且 firstReader 不是当前 thread
            HoldCounter rh = cachedHoldCounter; // 计数器
            // 计数器为空或者计数器上的 tid不是当前thread的tid
            if (rh == null || rh.tid != getThreadId(current))
            	// 获取当前thread的计数器
                cachedHoldCounter = rh = readHolds.get();
            else if (rh.count == 0)
            	// 数量是 0的话,set进去
                readHolds.set(rh);
            rh.count++;
        }
        return 1;
    }
    return fullTryAcquireShared(current);
}

代码细节分析:

  1. exclusiveCount(c),先判断 write 锁是否是0 ,不是的话,判断是否是当前线程,也不是的话,直接返回 -1
  2. !readerShouldBlock(), 判断该线程是否需要阻塞,需要的话 ,退出走 fullTryAcquireShared。
  3. r < MAX_COUNT, 判断下锁数量是否超出容量了,是的话,退出走 fullTryAcquireShared。
  4. compareAndSetState(c, c + SHARED_UNIT),CAS 设置 read 锁数量。 不成功的话,退出走 fullTryAcquireShared。
  5. (r == 0) ,上面步骤全部成功,如果 r ==0 也就是 read 锁数量是 0,那么设置第一个读线程firstReader和firstReaderHoldCount
  6. (firstReader == current),如果 r != 0 ,并且 firstReader == current,那么意味着重入,那么就直接 ++
  7. else,设置当前thread对应的HoldCounter的值。

=== 点击查看top目录 ===

四、lock.writeLock().lock() (写)剖析

  • 看下 WriteLock#lock 方法
public void ReentrantReadWriteLock.WriteLock#lock() {
    sync.acquire(1);
}
  • 看下 acquire 方法
public final void AbstractQueuedSynchronizer#acquire(int arg) {
    if (!tryAcquire(arg) && // 返回true的话,就是拿到lock了,无需往下走了
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) // tryAcquire返回了 false,走这里进入队列
        selfInterrupt();
}
  • 看下 tryAcquire 方法

protected final boolean ReentrantReadWriteLock.Sync#tryAcquire(int acquires) {
    Thread current = Thread.currentThread();
    int c = getState(); // 获取状态 
    int w = exclusiveCount(c); // 获取 write 锁数量
    if (c != 0) {
        // 如果 write 锁数量不是 0 或者说目前不是重入
        if (w == 0 || current != getExclusiveOwnerThread())
            return false; // 获取锁失败
        // 既然走到了这里,说明: w!= 0 && current == getExclusiveOwnerThread(),那么就是write数量不是0,并且是重入操作。
        if (w + exclusiveCount(acquires) > MAX_COUNT) //查看是否超限
            throw new Error("Maximum lock count exceeded");
        // Reentrant acquire
        setState(c + acquires); // 重入,状态 +1
        return true; //成功拿到锁
    }
    /*
     * 1. writer 是否应该阻塞。 NonfairSync一直不用阻塞。 FairSync的话,就看下队列中有没有排毒跌,有的话,就阻塞
     * 2. CAS 设置 state
     */
    if (writerShouldBlock() ||
        !compareAndSetState(c, c + acquires))
        return false; // 1.阻塞 或者:2.CAS设置status不成功。返回 false
    setExclusiveOwnerThread(current);
    return true;
}

=== 点击查看top目录 ===

五、场景分析

  1. 场景一:thread1 在 read,thread2-threadN 接着 read
  2. 场景二:thread1 在 read,thread1 准备来 write
  3. 场景三:thread1 在 read,thread2 准备来 write
  4. 场景四:thread1 在 read,thread1 重入 read (测试read重入)
  5. 场景五:thread1 在 write,thread2-N 准备来 read
  6. 场景六:thread1 在 write,thread2 准备来 write
  7. 场景七:thread1 在 write ,thread1 准备来 read (测试降级)
  8. 场景八:thread1 在 write, thread再次 write (测试write锁重入)

场景一:thread1 在 read,thread2-threadN 接着 read

代码:

public class _14_01_TestReadWriteLock {
    public static void main(String[] args) throws Exception {
        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        for (int i = 0; i < 5; i++) {
            new Thread(() -> {
                System.out.println(Thread.currentThread().getName() + " wait to lock ...");
                lock.readLock().lock();
                System.out.println(Thread.currentThread().getName() + " get the lock ... ===");
                System.out.println("点击任意键唤醒线程 ...");
                Scanner sc = new Scanner(System.in);
                sc.nextLine();
                try {
                    Thread.sleep(1000);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    System.out.println(Thread.currentThread().getName() + " ready to unlock ...");
                    lock.readLock().unlock();
                }
            }, "Read_" + i).start();
        }
    }
}

输出:

Read_0 wait to lock ...
Read_1 wait to lock ...
Read_1 get the lock ... ===
点击任意键唤醒线程 ...
Read_0 get the lock ... ===
点击任意键唤醒线程 ...
Read_2 wait to lock ...
Read_2 get the lock ... ===
点击任意键唤醒线程 ...
Read_3 wait to lock ...
Read_3 get the lock ... ===
点击任意键唤醒线程 ...
Read_4 wait to lock ...
Read_4 get the lock ... ===
点击任意键唤醒线程 ...


Read_3 ready to unlock ...
Read_2 ready to unlock ...
Read_1 ready to unlock ...
Read_0 ready to unlock ...
Read_4 ready to unlock ...

结论:

在第一个thread并未释放锁的时候,其他thread不阻塞,直接获取锁,往下跑。

=== 点击查看top目录 ===

场景二:thread1 在 read,thread1 准备来 write

看下代码:

public class _14_02_TestReadWriteLock {
	public static void main(String[] args) throws Exception{
		new Thread(() -> {
			ReadWriteLock lock = new ReentrantReadWriteLock();
			System.out.println(Thread.currentThread().getName() + " wait to read lock  ...");
			lock.readLock().lock();
			System.out.println(Thread.currentThread().getName() + " get the read lock ... ===");


			System.out.println(Thread.currentThread().getName() + " wait to lock write ...");
			lock.writeLock().lock();
			System.out.println(Thread.currentThread().getName() + " get the lock write ...");

			System.out.println(Thread.currentThread().getName() + " ready to unlock read ...");
			lock.readLock().unlock();

			System.out.println(Thread.currentThread().getName() + " ready to unlock write ...");
			lock.writeLock().unlock();
		}).start();
	}
}

输出:

Thread-0 wait to read lock  ...
Thread-0 get the read lock ... ===
Thread-0 wait to lock write ...
... 阻塞当中 ...

上面代码,read锁已经获得,但是write锁阻塞,read锁无法释放,上面死锁了。

注意上方的 c = getState() = 65536 ,刚刚好是 2的 16次方,因为read锁是在 高16位,所以 read 锁数量是1的话,那么就是 65536,真正的数量右移 16位。

在这里插入图片描述

在这里插入图片描述
=== 点击查看top目录 ===

场景三:thread1 在 read,thread2 准备来 write

同理,堵塞,等待 thread1 释放read 锁,释放后,可以获得锁

// 场景三:thread1 在 read,thread2 准备来 write
public class _14_03_TestReadWriteLock {
	public static void main(String[] args) throws Exception{
		ReadWriteLock lock = new ReentrantReadWriteLock();
		new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + " wait to read lock  ...");
			lock.readLock().lock();
			System.out.println(Thread.currentThread().getName() + " get the read lock ... ===");

			System.out.println("点击任意键唤醒线程 ...");
			Scanner sc = new Scanner(System.in);
			sc.nextLine();
			System.out.println(Thread.currentThread().getName() + " ready to unlock read ...");
			lock.readLock().unlock();

		}).start();

		Thread.sleep(2000);

		for (int i = 0; i < 5; i++) {
			new Thread(() -> {
				System.out.println(Thread.currentThread().getName() + " wait to lock write ...");
				lock.writeLock().lock();
				System.out.println(Thread.currentThread().getName() + " get the lock write ...");

				System.out.println(Thread.currentThread().getName() + " ready to unlock write ...");
				lock.writeLock().unlock();
			}).start();
		}
	}
}

输出:

Thread-0 wait to read lock  ...
Thread-0 get the read lock ... ===
点击任意键唤醒线程 ...
Thread-1 wait to lock write ...
Thread-2 wait to lock write ...
Thread-3 wait to lock write ...
Thread-4 wait to lock write ...
Thread-5 wait to lock write ...

Thread-0 ready to unlock read ...
Thread-1 get the lock write ...
Thread-1 ready to unlock write ...
Thread-2 get the lock write ...
Thread-2 ready to unlock write ...
Thread-3 get the lock write ...
Thread-3 ready to unlock write ...
Thread-4 get the lock write ...
Thread-4 ready to unlock write ...
Thread-5 get the lock write ...
Thread-5 ready to unlock write ...

=== 点击查看top目录 ===

场景四:thread1 在 read,thread1 重入 read (测试read重入)

代码:

// 场景四:thread1 在 read,thread1 重入 read
public class _14_07_TestReadWriteLock {
    public static void main(String[] args) throws Exception {
        new Thread(() -> {
            ReadWriteLock lock = new ReentrantReadWriteLock();

            System.out.println(Thread.currentThread().getName() + " wait to read lock ...");
            lock.readLock().lock();
            System.out.println(Thread.currentThread().getName() + " get the read lock ... ===");

            lock.readLock().lock();
            System.out.println(Thread.currentThread().getName() + " get the read lock2 ... ===");

            lock.readLock().lock();
            System.out.println(Thread.currentThread().getName() + " get the read lock3 ... ===");


            System.out.println(Thread.currentThread().getName() + " ready to read unlock ...");
            lock.readLock().unlock();

            System.out.println(Thread.currentThread().getName() + " ready to read unlock2 ...");
            lock.readLock().unlock();

            System.out.println(Thread.currentThread().getName() + " ready to read unlock3 ...");
            lock.readLock().unlock();
        }).start();
    }
}

输出:

Thread-0 wait to read lock ...
Thread-0 get the read lock ... ===
Thread-0 get the read lock2 ... ===
Thread-0 get the read lock3 ... ===
Thread-0 ready to read unlock ...
Thread-0 ready to read unlock2 ...
Thread-0 ready to read unlock3 ...

场景五:thread1 在 write,thread2-N 准备来 read

代码:

public class _14_05_TestReadWriteLock {
	public static void main(String[] args) throws Exception{
		ReadWriteLock lock = new ReentrantReadWriteLock();
		new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + " wait to write lock  ...");
			lock.writeLock().lock();
			System.out.println(Thread.currentThread().getName() + " get the write lock ... ===");

			System.out.println("点击任意键唤醒线程 ...");
			Scanner sc = new Scanner(System.in);
			sc.nextLine();
			System.out.println(Thread.currentThread().getName() + " ready to unlock write ...");
			lock.writeLock().unlock();

		}).start();

		Thread.sleep(5000);

		for (int i = 0; i < 5; i++) {
			new Thread(() -> {
				System.out.println(Thread.currentThread().getName() + " wait to read lock  ... ");
				lock.readLock().lock();
				System.out.println(Thread.currentThread().getName() + " get the read lock ... ===");
				System.out.println(Thread.currentThread().getName() + " ready to read unlock  ...");
				lock.readLock().unlock();
			}).start();
		}
	}
}

输出:

Thread-0 wait to write lock  ...
Thread-0 get the write lock ... ===
点击任意键唤醒线程 ...
Thread-1 wait to read lock  ... 
Thread-2 wait to read lock  ... 
Thread-3 wait to read lock  ... 
Thread-4 wait to read lock  ... 
Thread-5 wait to read lock  ... 

Thread-0 ready to unlock write ...
Thread-1 get the read lock ... ===
Thread-1 ready to read unlock  ...
Thread-2 get the read lock ... ===
Thread-2 ready to read unlock  ...
Thread-3 get the read lock ... ===
Thread-3 ready to read unlock  ...
Thread-5 get the read lock ... ===
Thread-5 ready to read unlock  ...
Thread-4 get the read lock ... ===
Thread-4 ready to read unlock  ...

read共享锁解析

在这里插入图片描述

=== 点击查看top目录 ===

场景六:thread1 在 write,thread2 准备来 write

代码

public class _14_06_TestReadWriteLock {
	public static void main(String[] args) throws Exception{
		ReadWriteLock lock = new ReentrantReadWriteLock();
		new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + " wait to write lock  ...");
			lock.writeLock().lock();
			System.out.println(Thread.currentThread().getName() + " get the write lock ... ===");

			System.out.println("点击任意键唤醒线程 ...");
			Scanner sc = new Scanner(System.in);
			sc.nextLine();
			System.out.println(Thread.currentThread().getName() + " ready to unlock write ...");
			lock.writeLock().unlock();
		}).start();

		Thread.sleep(5000);

		new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + " wait to write lock  ... ");
			lock.writeLock().lock();
			System.out.println(Thread.currentThread().getName() + " get the write lock ... ===");
			System.out.println(Thread.currentThread().getName() + " ready to write unlock  ...");
			lock.writeLock().unlock();
		}).start();
	}
}

输出:

Thread-0 wait to write lock  ...
Thread-0 get the write lock ... ===
点击任意键唤醒线程 ...
Thread-1 wait to write lock  ... 

Thread-0 ready to unlock write ...
Thread-1 get the write lock ... ===
Thread-1 ready to write unlock  ...

场景七:thread1 在 write ,thread1 准备来 read (测试降级)

代码:

public class _14_07_TestReadWriteLock {
	public static void main(String[] args) throws Exception{
		new Thread(() -> {
			ReadWriteLock lock = new ReentrantReadWriteLock();

			System.out.println(Thread.currentThread().getName() + " wait to write lock ...");
			lock.writeLock().lock();
			System.out.println(Thread.currentThread().getName() + " get the write lock ... ===");

			System.out.println(Thread.currentThread().getName() + " wait to read lock ...");
			lock.readLock().lock();
			System.out.println(Thread.currentThread().getName() + " get the read lock  ... ===");

			System.out.println(Thread.currentThread().getName() + " ready to unlock read...");
			lock.readLock().unlock();

			System.out.println(Thread.currentThread().getName() + " ready to unlock write ...");
			lock.writeLock().unlock();
		}).start();
	}
}

输出:

Thread-0 wait to write lock ...
Thread-0 get the write lock ... ===
Thread-0 wait to read lock ...
Thread-0 get the read lock  ... ===
Thread-0 ready to unlock read...
Thread-0 ready to unlock write ...

看下图: 在 write锁被持有,并且getExclusiveOwnerThread() == current的情况下,顺利拿到 read 锁。

=== 点击查看top目录 ===

场景八:thread1 在 write, thread再次 write (测试write锁重入)

代码

// 场景八:thread1 在 write, thread再次 write (测试write锁重入)
public class _14_08_TestReadWriteLock {
    public static void main(String[] args) throws Exception {
        new Thread(() -> {
            ReadWriteLock lock = new ReentrantReadWriteLock();

            System.out.println(Thread.currentThread().getName() + " wait to write lock ...");
            lock.writeLock().lock();
            System.out.println(Thread.currentThread().getName() + " get the write lock ... ===");

            lock.writeLock().lock();
            System.out.println(Thread.currentThread().getName() + " get the write lock2 ... ===");

            lock.writeLock().lock();
            System.out.println(Thread.currentThread().getName() + " get the write lock3 ... ===");

            System.out.println(Thread.currentThread().getName() + " ready to write unlock ...");
            lock.writeLock().unlock();

            System.out.println(Thread.currentThread().getName() + " ready to write unlock2 ...");
            lock.writeLock().unlock();

            System.out.println(Thread.currentThread().getName() + " ready to write unlock3 ...");
            lock.writeLock().unlock();
        }).start();
    }
}

输出:

Thread-0 wait to write lock ...
Thread-0 get the write lock ... ===
Thread-0 get the write lock2 ... ===
Thread-0 get the write lock3 ... ===
Thread-0 ready to write unlock ...
Thread-0 ready to write unlock2 ...
Thread-0 ready to write unlock3 ...

六、各个场景的分析结论:

  1. thread1 拿到read锁的时候,thread2想read可以。(共享锁可以共享)
  2. thread1 拿到read锁的时候,thread1想write不行。(锁无法升级)
  3. thread1 拿到read锁的时候,thread2想write不行。
  4. thread1 拿到read锁的时候,thread1想再次read可以。 (重入ok)
  5. thread1 拿到write锁的时候,thread2想read不行。(独占锁不允许共享)
  6. thread1 拿到write锁的时候,thread2 想 write不行。(独占锁不允许共享)
  7. thread1 拿到write锁的时候,thread1想read可以。(锁降级了)
  8. thread1 拿到write锁的时候,thread1想write可以。 (重入ok)

所以:

  1. 一个线程要想同时持有写锁和读锁,必须先获取写锁再获取读锁;
  2. 写锁可以“降级”为读锁;读锁不能“升级”为写锁。

=== 点击查看top目录 ===

七、write 锁释放 tryRelease

protected final boolean ReentrantReadWriteLock.Sync#tryRelease(int releases) {
    //若锁的持有者不是当前线程,抛出异常
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    //写锁的新线程数,正常-1
    int nextc = getState() - releases;
    //如果独占模式重入数为0了,说明独占模式write锁被释放
    boolean free = exclusiveCount(nextc) == 0;
    if (free)
        //若write锁的新线程数为0,则将锁的持有者设置为null
        setExclusiveOwnerThread(null);
    //设置写锁的新线程数
    //不管独占模式是否被释放,更新独占重入数
    setState(nextc);
    return free;
}

=== 点击查看top目录 ===

八、read 锁释放 tryReleaseShared

protected final boolean tryReleaseShared(int unused) {
    // 获取当前线程
    Thread current = Thread.currentThread();
    if (firstReader == current) { // 当前线程为第一个读线程
        // assert firstReaderHoldCount > 0;
        if (firstReaderHoldCount == 1) // read 线程占用的资源数为1
            firstReader = null;
        else // 减少占用的资源
            firstReaderHoldCount--;
    } else { // 当前线程不为第一个读线程
        // 获取缓存的计数器
        HoldCounter rh = cachedHoldCounter;
        if (rh == null || rh.tid != getThreadId(current)) // 计数器为空或者计数器的tid不为当前正在运行的线程的tid
            // 获取当前线程对应的计数器
            rh = readHolds.get();
        // 获取计数
        int count = rh.count;
        if (count <= 1) { // 计数小于等于1
            // 移除
            readHolds.remove();
            if (count <= 0) // 计数小于等于0,抛出异常
                throw unmatchedUnlockException();
        }
        // 减少计数
        --rh.count;
    }
    for (;;) { // 无限循环
        // 获取状态
        int c = getState();
        // 获取状态
        int nextc = c - SHARED_UNIT;
        if (compareAndSetState(c, nextc)) // 比较并进行设置
            return nextc == 0;
    }
}

=== 点击查看top目录 ===

九、结论

而readwrite锁有以下三个重要的特性:

(1)公平选择性:支持非公平(默认)和公平的锁获取方式,吞吐量还是非公平优于公平。

(2)重进入:读锁和写锁都支持线程重进入。

(3)锁降级:遵循获取写锁、获取读锁再释放写锁的次序,写锁能够降级成为读锁

=== 点击查看top目录 ===

十、番外篇

下一章节:【线程】线程八锁与Synchronzied内部原理(十二)
上一章节:【线程】ReentrantLock 内部公平锁与非公平锁实现 (十)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章