现在线程5要加写锁,阻塞在队列里了。
image.png
从unlock方法下去
image.png

tryReleaseShared,尝试释放锁也就是改变state状态

  1. protected final boolean tryReleaseShared(int unused) {
  2. //暂时不关心
  3. Thread current = Thread.currentThread();
  4. if (firstReader == current) {
  5. // assert firstReaderHoldCount > 0;
  6. if (firstReaderHoldCount == 1)
  7. firstReader = null;
  8. else
  9. firstReaderHoldCount--;
  10. } else {
  11. HoldCounter rh = cachedHoldCounter;
  12. if (rh == null || rh.tid != getThreadId(current))
  13. rh = readHolds.get();
  14. int count = rh.count;
  15. if (count <= 1) {
  16. readHolds.remove();
  17. if (count <= 0)
  18. throw unmatchedUnlockException();
  19. }
  20. --rh.count;
  21. }
  22. //开始释放读锁
  23. for (;;) {
  24. int c = getState();
  25. int nextc = c - SHARED_UNIT;
  26. if (compareAndSetState(c, nextc))
  27. // Releasing the read lock has no effect on readers,
  28. // but it may allow waiting writers to proceed if
  29. // both read and write locks are now free.
  30. return nextc == 0;
  31. }
  32. }
  1. int c = getState();获取state
  2. int nextc = c - SHARED_UNIT; 从高16位扣除掉读锁加锁次数;
  3. compareAndSetState(c, nextc) cas替换state变量
  4. return nextc == 0; 读锁加锁次数都释放完了,nextc就是0,因此就返回true。如果没有释放完就得等外部在执行一次unlock操作了。

    doReleaseShared,唤醒线程

    1. private void doReleaseShared() {
    2. /*
    3. * Ensure that a release propagates, even if there are other
    4. * in-progress acquires/releases. This proceeds in the usual
    5. * way of trying to unparkSuccessor of head if it needs
    6. * signal. But if it does not, status is set to PROPAGATE to
    7. * ensure that upon release, propagation continues.
    8. * Additionally, we must loop in case a new node is added
    9. * while we are doing this. Also, unlike other uses of
    10. * unparkSuccessor, we need to know if CAS to reset status
    11. * fails, if so rechecking.
    12. */
    13. for (;;) {
    14. Node h = head;
    15. if (h != null && h != tail) {
    16. int ws = h.waitStatus;
    17. if (ws == Node.SIGNAL) {
    18. if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
    19. continue; // loop to recheck cases
    20. unparkSuccessor(h);
    21. }
    22. else if (ws == 0 &&
    23. !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
    24. continue; // loop on failed CAS
    25. }
    26. if (h == head) // loop if head changed
    27. break;
    28. }
    29. }
  5. Node h = head;

image.png

  1. ws == Node.SIGNAL;这一步肯定是要进去的。
  2. !compareAndSetWaitStatus(h, Node.SIGNAL, 0);这一步假设cas成功了,即便不成功因为有for循环还是能设置成功的

image.png

  1. unparkSuccessor(h);按队列顺序释放线程,这个是所有唤醒线程的公用方法。