赞
踩
对于 AQS 来说,线程同步的关键是对 state 的操作,可以说获取、释放资源是否成功都是由 state 决定的
比如 state>0 代表可获取资源,否则无法获取,所以 state 的具体语义由实现者去定义,现有的 ReentrantLock、ReentrantReadWriteLock、Semaphore、CountDownLatch 定义的 state 语义都不一样
getState、setState、以及compareAndSwapInt三个方法均是原子操作,其中 compareAndSetState 的实现依赖于Unsafe类的compareAndSwapInt()方法
/**
* The synchronization state.
*/
private volatile int state;
getState()
setState()
compareAndSetState()
Node
的形式定义了同步队列结点static final class Node { /** 模式定义 */ static final Node SHARED = new Node(); static final Node EXCLUSIVE = null; /** 线程状态 */ static final int CANCELLED = 1; static final int SIGNAL = -1; static final int CONDITION = -2; static final int PROPAGATE = -3; /** 线程等待状态 */ volatile int waitStatus; /** 前驱结点 */ volatile Node prev; /** 后置结点 */ volatile Node next; /** 持有的线程对象 */ volatile Thread thread; /** 对于独占模式而言,指向下一个处于 CONDITION 等待状态的结点;对于共享模式而言,则为 SHARED 结点 */ Node nextWaiter; // ... 省略方法定义 }
waitStatus 有如下 5 中状态:
/**
* Head of the wait queue, lazily initialized. Except for
* initialization, it is modified only via method setHead. Note:
* If head exists, its waitStatus is guaranteed not to be
* CANCELLED.
*/
private transient volatile Node head;
/**
* Tail of the wait queue, lazily initialized. Modified only via
* method enq to add new wait node.
*/
private transient volatile Node tail;
同步队列的主要行为是 :入队、出队
/** * Creates and enqueues node for current thread and given mode. * * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared * @return the new node */ private Node addWaiter(Node mode) { Node node = new Node(mode); for (;;) { Node oldTail = tail; if (oldTail != null) { node.setPrevRelaxed(oldTail); if (compareAndSetTail(oldTail, node)) { oldTail.next = node; return node; } } else { initializeSyncQueue(); } } }
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { // 如果 state=0 了,就是可以释放锁了 free = true; setExclusiveOwnerThread(null); // 将拿锁线程置为 null } setState(c); // 重置同步器的 state return free; // 返回是否成功释放 } private void unparkSuccessor(Node node) { // node 节点是当前释放锁的节点,也是同步队列的头节点 int ws = node.waitStatus; // 如果节点已经被取消了,把节点的状态置为初始化 if (ws < 0) compareAndSetWaitStatus(node, ws, 0); // 拿出队二 s Node s = node.next; // s 为空,表示 node 的后一个节点为空 // s.waitStatus 大于 0,代表 s 节点已经被取消了 // 遇到以上这两种情况,就从队尾开始,向前遍历,找到第一个 waitStatus 字段不是被取消的 if (s == null || s.waitStatus > 0) { s = null; // 结束条件是前置节点就是 head 了 for (Node t = tail; t != null && t != node; t = t.prev) // t.waitStatus <= 0 说明 t 当前没有被取消,肯定还在等待被唤醒 if (t.waitStatus <= 0) s = t; } // 唤醒以上代码找到的线程 if (s != null) LockSupport.unpark(s.thread); }
总结:出队列,锁释放唤醒 head 的后继节点,head 的后继节点从阻塞中醒来,开始抢锁,获取锁成功,此时 head 指针向后移一个位置,原先 head 的后继节点成为新的 head。
private Lock lock = new ReentrantLock();
private Condition FirstCond = lock.newCondition();
private Condition SecondCond = lock.newCondition();
ReentrantLock是可重入的独占锁,只能有一个线程可以获取该锁,其它获取该锁的线程会被阻塞。
可重入表示当前线程获取该锁后再次获取不会被阻塞,也就意味着同一个线程可以多次获得同一个锁而不会发生死锁。
ReentrantLock 的加锁和解锁:
new ReentrantLock()
默认创建的是非公平锁 NonfairSync。
// 创建非公平锁
ReentrantLock lock = new ReentrantLock();
// 获取锁操作
lock.lock();
try {
// 执行代码逻辑
} catch (Exception ex) {
// ...
} finally {
// 解锁操作
lock.unlock();
}
unlock()
方法时,ReentrantLock 会将持有锁的计数减 1,如果计数到达 0,则释放锁,并唤醒等待队列中的线程来竞争锁Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。