读锁

tryAcquireShared()

加锁失败则返回-1 成功则返回>0
tryAcquireShared(arg) < 0
image.png
image.png

加锁

image.png
image.png
image.png
image.png
1. 在获取读锁时,会尝试判断当前对象是否拥有了写锁(排它),如果已经拥有,则直接失败。
2. 如果没有写锁,就表示当前对象没有排他锁,则当前线程会尝试给对象加锁
3. 如果当前线程已经持有了该对象的读锁,那么直接将读锁数量加1

  1. protected final int tryAcquireShared(int unused) {
  2. //这里主要是为了性能 缓存了第一次和最后一次加锁的信息
  3. Thread current = Thread.currentThread();
  4. int c = getState();
  5. //首先判断是否被上了写锁
  6. //exclusiveCount(c) != 0 标识上了写锁
  7. //但是还会继续判断为什么上了写锁还要继续判断-----》重入或者降级
  8. //然后再判断是否是重入如果这里是重入则一定是降级 如果不是重入则失败 读写需要互斥
  9. if (exclusiveCount(c) != 0 &&
  10. getExclusiveOwnerThread() != current)
  11. return -1;
  12. //如果上面代码没有返回,执行到这里,有两种情况标识1、没有人上写锁 2、重入降级
  13. int r = sharedCount(c);//得到r的上锁次数
  14. if (!readerShouldBlock() && r < MAX_COUNT && compareAndSetState(c, c + SHARED_UNIT)) {
  15. //r 是加锁之前的
  16. //r == 0 标识 这是第一次给这把锁加读锁 之前没有人加锁
  17. if (r == 0) {
  18. //如果是第一个线程第一次加锁(之前没有人加过锁),则把这个线程付给firstReader 局部变量
  19. firstReader = current;
  20. //记录一下当前线程的加锁次数
  21. firstReaderHoldCount = 1;
  22. } else if (firstReader == current) {
  23. //重入
  24. firstReaderHoldCount++;
  25. } else {
  26. HoldCounter rh = cachedHoldCounter;
  27. if (rh == null || rh.tid != getThreadId(current))
  28. cachedHoldCounter = rh = readHolds.get();
  29. else if (rh.count == 0)
  30. readHolds.set(rh);
  31. rh.count++;
  32. }
  33. //加锁成功
  34. return 1;
  35. }
  36. return fullTryAcquireShared(current);
  37. }

加锁失败 阻塞

    private void doAcquireShared(int arg) {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    //被唤醒时再去拿锁
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        //如果队列中自己的后面也是读锁,把它也唤醒
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    //如果被唤醒,从这里开始
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

往后依次唤醒自己后面的读锁

image.png