ReentrantLock类的hasQueuedPredecessors方法

部分启发来源自文章:Java并发编程--Lock

PART 1

1、如果h==t成立,h和t均为null或是同一个具体的节点,无后继节点,返回false。
2、如果h!=t成立,head.next是否为null,如果为null,返回true。什么情况下h!=t的同时h.next==null??,有其他线程第一次正在入队时,可能会出现。见AQS的enq方法,compareAndSetHead(node)完成,还没执行tail=head语句时,此时tail=null,head=newNode,head.next=null。
3、如果h!=t成立,head.next==null,则判断head.next是否是当前线程,如果是返回false,否则返回true(head节点是获取到锁的节点,但是任意时刻head节点可能占用着锁,也可能释放了锁(unlock()),未被阻塞的head.next节点对应的线程在任意时刻都是有必要去尝试获取锁)

1 public final boolean hasQueuedPredecessors() {
2     Node t = tail; 
3     Node h = head;
4     Node s;
5     return h != t &&
6         ((s = h.next) == null || s.thread != Thread.currentThread());
7 }

PART 2  解释为什么要判断:s.thread != Thread.currentThread()

根据ReentrantLock的解锁流程,也就是下面四个方法,可以看到当线程释放锁之后还是会在队列的head节点,只是把next指针指向下一个可用节点,并唤醒它
也就是说任意时刻,head节点可能占用着锁,也可能释放了锁(unlock()),未被阻塞的head.next节点对应的线程在任意时刻都是有必要去尝试获取锁

1 public void unlock() {
2     sync.release(1);
3 }

尝试释放锁,释放成功后把head.next从阻塞中唤醒

1 public final boolean release(int arg) {
2     if (tryRelease(arg)) {
3         Node h = head;
4         if (h != null && h.waitStatus != 0)
5             unparkSuccessor(h);
6         return true;
7     }
8     return false;
9 }

把state-1
当state=0时,把exclusiveOwnerThread设置为null,说明线程释放了锁

 1 protected final boolean tryRelease(int releases) {
 2     int c = getState() - releases;
 3     if (Thread.currentThread() != getExclusiveOwnerThread())
 4         throw new IllegalMonitorStateException();
 5     boolean free = false;
 6     if (c == 0) {
 7         free = true;
 8         setExclusiveOwnerThread(null);
 9     }
10     setState(c);
11     return free;
12 }

把head.next指向下一个waitStatus<=0的节点,并把该节点从阻塞中唤醒

 1 private void unparkSuccessor(Node node) {
 2     int ws = node.waitStatus;
 3     if (ws < 0)
 4         compareAndSetWaitStatus(node, ws, 0);
 5 
 6     Node s = node.next;
 7     if (s == null || s.waitStatus > 0) {
 8         // 这里没看懂为什么要从tail节点倒序遍历?
 9         // 不是应该从head.next节点开始遍历更快嘛?
10         s = null;
11         for (Node t = tail; t != null && t != node; t = t.prev)
12             if (t.waitStatus <= 0)
13                 s = t;
14     }
15     if (s != null)
16         LockSupport.unpark(s.thread);
17 }

猜你喜欢

转载自www.cnblogs.com/kumu/p/10659835.html
今日推荐