J.U.C — Locks — ReentrantLock(二)
来源:互联网 发布:服装设计要学什么软件 编辑:程序博客网 时间:2024/06/10 18:46
条件变量Condition
Condition实现了synchronized同步器的wait/notify/notifyAll的功能,Condition接口提供的API如下:
Condition需要与Lock绑定,一个Lock可以有多个Condition,获取Condition的方式是lock.newCondition()。Condition的实现类在AQS中的ConditionObject,类部维持了一个等待队列:
- 获取Condition
lock.newCondition() -->// ReentrantLockpublic Condition newCondition() { return sync.newCondition();}// ReentrantLock.Syncfinal ConditionObject newCondition() { return new ConditionObject();} --> // AQS.ConditionObject public ConditionObject() { }
- await()
public final void await() throws InterruptedException { if (Thread.interrupted()) // 如果当前线程被终端,抛出异常 throw new InterruptedException(); Node node = addConditionWaiter(); // 1. 将当前线程添加到Condition队列 int savedState = fullyRelease(node); // 2. 释放锁 int interruptMode = 0; while (!isOnSyncQueue(node)) { // 3. 自旋直到被signal或signalAll唤醒 LockSupport.park(this); // 挂起当前线程 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) // 4. 自旋去获取锁 interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); } // 1. private Node addConditionWaiter() { Node t = lastWaiter; // If lastWaiter is cancelled, clean out. if (t != null && t.waitStatus != Node.CONDITION) { unlinkCancelledWaiters(); t = lastWaiter; } Node node = new Node(Thread.currentThread(), Node.CONDITION); if (t == null) firstWaiter = node; else t.nextWaiter = node; lastWaiter = node; return node; } // 2. final int fullyRelease(Node node) { boolean failed = true; try { int savedState = getState(); if (release(savedState)) { // 调用release方法释放锁 failed = false; return savedState; } else { throw new IllegalMonitorStateException(); } } finally { if (failed) node.waitStatus = Node.CANCELLED; } } // 3. final boolean isOnSyncQueue(Node node) { if (node.waitStatus == Node.CONDITION || node.prev == null) return false; if (node.next != null) // If has successor, it must be on queue return true; return findNodeFromTail(node); } private boolean findNodeFromTail(Node node) { // 在sync队列中从尾部到头部查找是不是在sync队列中 Node t = tail; for (;;) { if (t == node) return true; if (t == null) return false; t = t.prev; } }
- signal()
public final void signal() { if (!isHeldExclusively()) // 1. 判断是不是当前线程持有锁,只有持有锁的线程能唤醒其他等待的线程 throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignal(first); // 2. 通知Condition队列中的等待最长时间的线程,即firstWaiter }// ReentrantLock.Sync// 1.protected final boolean isHeldExclusively() { return getExclusiveOwnerThread() == Thread.currentThread();} // 2. private void doSignal(Node first) { do { if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; } while (!transferForSignal(first) && (first = firstWaiter) != null); } final boolean transferForSignal(Node node) { if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; Node p = enq(node); // 将节点加入sync队列 int ws = p.waitStatus; if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; }
事例
假设现在有三个线程陆续调用同一个condition的await- 开始状态:thread-1获取锁
- thread-1调用await():
用thread-1创建节点,并设置waitStatus= -2(Condition),再将thread-1加入Condition队列,队列为空,将firstWaiter和lastWaiter设为thread-1;调用release释放thread-1拥有的锁,并从Sync队列中移除节点;自旋等待唤醒
- thread-2调用await():
- thread-3调用await():
- 当收到signal信号后,会从condition队列中从头开始将节点移到sync队列,并唤醒自旋获取锁
0 0
- J.U.C — Locks — ReentrantLock(二)
- J.U.C — Locks — ReentrantLock(一)
- J.U.C--locks--ReentrantLock
- 【Java并发编程实战】—–“J.U.C”:ReentrantLock之二lock方法分析
- 【Java并发编程实战】—–“J.U.C”:ReentrantLock之二lock方法分析
- J.U.C--locks--Condition
- J.U.C.Locks 体系结构
- “J.U.C”:ReentrantLock之二lock方法分析 (r)
- “J.U.C”:ReentrantLock之二lock方法分析
- J.U.C--locks--AQS分析
- 【Java并发编程实战】—–“J.U.C”:ReentrantLock之一简介
- 【Java并发编程实战】—–“J.U.C”:ReentrantLock之一简介
- “J.U.C”:ReentrantLock之一简介 (r)
- “J.U.C”:ReentrantLock之一简介
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之二lock方法分析
- “J.U.C”:ReentrantLock之三unlock方法分析(r)
- 【Java并发编程实战】-----“J.U.C”:ReentrantLock之一简介
- 【死磕Java并发】-----J.U.C之重入锁:ReentrantLock
- KMP算法(2):其细微之处
- 指针作为参数传入函数的陷阱
- 顺序与选择结构
- PMA,时间序列模型的二维扩展
- 详述 Cookie 与 Session 的区别
- J.U.C — Locks — ReentrantLock(二)
- hihoCoder Demo Day dp
- C值传递和引用传递
- POJ 3279 Fliptile
- Dubbo之——Dubbo 管理控制台的安装
- 空指针赋值问题(树的非递归遍历)
- 支付SDK
- linux常用命令
- swing树形图