ReentrantLock 分为公平锁和非公平锁, 默认的为非公平锁
- public ReentrantLock() {sync = new NonfairSync();
- }
可以手动指定
- public ReentrantLock(boolean fair) {
- sync = fair ? new FairSync() : new NonfairSync();
- }
先从非公平锁讲起
- 1 lock
- final void lock() {
- if (compareAndSetState(0, 1))
- setExclusiveOwnerThread(Thread.currentThread());
- else
- acquire(1);
- }
首先尝试 cas 把 state 设置为 1, 如果成功则获取独占锁, 失败执行 acquire
- 2 acquire
- public final void acquire(int arg) {
- if (!tryAcquire(arg) &&
- acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
- selfInterrupt();
- }
- 2.1 tryAcquire
- protected final boolean tryAcquire(int acquires) {
- return nonfairTryAcquire(acquires);
- }
- final boolean nonfairTryAcquire(int acquires) {
- final Thread current = Thread.currentThread();
- int c = getState();
- if (c == 0) {
- if (compareAndSetState(0, acquires)) {
- setExclusiveOwnerThread(current);
- return true;
- }
- }
- else if (current == getExclusiveOwnerThread()) {
- int nextc = c + acquires;
- if (nextc <0) // overflow
- throw new Error("Maximum lock count exceeded");
- setState(nextc);
- return true;
- }
- return false;
- }
先获取当前独占锁的数量:
1. 如果为 0, 则 cas 获取锁, 成功则获取独占锁
2. 如果不为 0, 则检查当前线程是否是重入锁, 是就独占锁数量加一并返回
2.2.1 addWaiter
如果 tryAcquire 都失败, 那么就执行入队操作
- private Node addWaiter(Node mode) {
- Node node = new Node(Thread.currentThread(), mode);
- // Try the fast path of enq; backup to full enq on failure
- Node pred = tail;
- if (pred != null) {
- node.prev = pred;
- if (compareAndSetTail(pred, node)) {
- pred.next = node;
- return node;
- }
- }
- enq(node);
- return node;
- }
如果尾节点不为空, 执行一次快速入队操作, 如果 cas 成功, 就入队成功
尾节点为空或者快速入队不成功, for 循环执行入队直到成功
- private Node enq(final Node node) {
- for (;;) {
- Node t = tail;
- if (t == null) { // Must initialize
- if (compareAndSetHead(new Node()))
- tail = head;
- } else {
- node.prev = t;
- if (compareAndSetTail(t, node)) {
- t.next = node;
- return t;
- }
- }
- }
- }
这里有个生成空节点的操作, 因为在存在队列的情况下, 队列头节点表示的是当前拥有锁的线程
2.2.1 acquireQueued
节点入队成功之后再执行线程挂起
- final boolean acquireQueued(final Node node, int arg) {
- boolean failed = true;
- try {
- boolean interrupted = false;
- for (;;) {
- final Node p = node.predecessor();
- if (p == head && tryAcquire(arg)) {
- setHead(node);
- p.next = null; // help GC
- failed = false;
- return interrupted;
- }
- if (shouldParkAfterFailedAcquire(p, node) &&
- parkAndCheckInterrupt())
- interrupted = true;
- }
- } finally {
- if (failed)
- cancelAcquire(node);
- }
- }
注意
p == head && tryAcquire(arg)
这个条件是这个函数的唯一出口, 先看线程挂起部分
- p == head && tryAcquire(arg)
- private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
- int ws = pred.waitStatus;
- if (ws == Node.SIGNAL)
- /*
- * This node has already set status asking a release
- * to signal it, so it can safely park.
- */
- return true;
- if (ws> 0) {
- /*
- * Predecessor was cancelled. Skip over predecessors and
- * indicate retry.
- */
- do {
- node.prev = pred = pred.prev;
- } while (pred.waitStatus> 0);
- pred.next = node;
- } else {
- /*
- * waitStatus must be 0 or PROPAGATE. Indicate that we
- * need a signal, but don't park yet. Caller will need to
- * retry to make sure it cannot acquire before parking.
- */
- compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
- }
- return false;
- }
判断前置节点的状态, 在这里分为三种情况:
1.Node.SIGNAL, 可以唤醒后继节点, 表示可以挂起单钱节点线程, 所以直接返回
2. 大于 0, 表示取消状态, 则往前遍历删除节点直至非取消状态
3. 如果不是前两者, 将前置节点置为 Node.SIGNAL
线程挂起
- private final boolean parkAndCheckInterrupt() {
- LockSupport.park(this);
- return Thread.interrupted();
- }
- 2.3 selfInterrupt
- static void selfInterrupt() {
- Thread.currentThread().interrupt();
- }
这是一个比较细节的地方, 结合挂起部分看
线程挂起的方式是采用 LockSupport.park, 能够响应中断, 但是不会抛异常也就是说挂起的线程有可能被 ReentrantLock 之外的线程唤醒, 这时候就需要重置中断状态, 并且保证线程正确被唤醒并获取锁的时候, 保持中断状态
3 unlock
采用 LockSupport.unpark 唤醒队列下一个线程
再来看公平锁
其实差别就两点:
1. 没有直接 cas 获取锁的操作
2. 在获取锁数量为 0 的时候, 不再直接进行 cas 操作, 要先判断下队列中是否还有节点未执行
- protected final boolean tryAcquire(int acquires) {
- final Thread current = Thread.currentThread();
- int c = getState();
- if (c == 0) {
- if (!hasQueuedPredecessors() &&
- compareAndSetState(0, acquires)) {
- setExclusiveOwnerThread(current);
- return true;
- }
- }
- else if (current == getExclusiveOwnerThread()) {
- int nextc = c + acquires;
- if (nextc < 0)
- throw new Error("Maximum lock count exceeded");
- setState(nextc);
- return true;
- }
- return false;
- }
- }
来源: http://www.jianshu.com/p/810f569e47f5