可重入锁ReentrantLock解析

说到可重入锁,先从AQS的ConditionObject说起,AQS的内部类ConditionObject是构建显示锁条件队列的基础。之前AQS的解析没有说这个内部类,这里和ReentrantLock一起说一下。

1、AQS的内部类ConditionObject

addConditionWaiter方法的代码:

这个方法的作用是将当前线程封装好放到条件队列。

 1     private Node addConditionWaiter() {
 2             Node t = lastWaiter;
 3             // If lastWaiter is cancelled, clean out.
 4             if (t != null && t.waitStatus != Node.CONDITION) {//如果等待队列的最后一个是取消状态,就把遍历整个队列把所有取消状态的节点清除
 5                 unlinkCancelledWaiters();
 6                 t = lastWaiter;
 7             }
 8             Node node = new Node(Thread.currentThread(), Node.CONDITION);//以当前线程新建一个节点
 9             if (t == null)//根据条件将节点放入队列
10                 firstWaiter = node;
11             else
12                 t.nextWaiter = node;
13             lastWaiter = node;
14             return node;//返回当前线程的节点
15         }

doSignal方法的代码:

这个方法的作用就是唤醒当前线程。

1         private void doSignal(Node first) {
2             do {
3                 if ( (firstWaiter = first.nextWaiter) == null)
4                     lastWaiter = null;
5                 first.nextWaiter = null;
6             } while (!transferForSignal(first) &&//调用了transferForSignal方法
7                      (first = firstWaiter) != null);
8         }

transferForSignal方法的代码:

 1     final boolean transferForSignal(Node node) {
 2         /*
 3          * If cannot change waitStatus, the node has been cancelled.
 4          */
 5         if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))//cas修改值,如果成功等待到了条件成立;如果失败节点的状态改为了CANCELLED,直接返回
 6             return false;
 7 
 8         /*
 9          * Splice onto queue and try to set waitStatus of predecessor to
10          * indicate that thread is (probably) waiting. If cancelled or
11          * attempt to set waitStatus fails, wake up to resync (in which
12          * case the waitStatus can be transiently and harmlessly wrong).
13          */
14         Node p = enq(node);//节点入队 这里可能会有点晕,这个节点不是刚从队列里取出吗,怎么又入队了 其实是因为队列不是同一个,每个ConditionObject对象都有一个条件队列,队列里的节点等待的条件成立了会被添加到AQS的队列,这时节点(线程)才有资格等待获取资源
15         int ws = p.waitStatus;
16         if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))//唤醒线程
17             LockSupport.unpark(node.thread);
18         return true;
19     }

doSignalAll方法的代码:

这个方法的作用就是唤醒所有节点(线程)。

1         private void doSignalAll(Node first) {
2             lastWaiter = firstWaiter = null;
3             do {
4                 Node next = first.nextWaiter;
5                 first.nextWaiter = null;
6                 transferForSignal(first);
7                 first = next;
8             } while (first != null);
9         }

unlinkCancelledWaiters方法的代码:

这个方法被上面说的addConditionWaiter方法调用,将队列的取消状态的节点(线程)清除。

 1         private void unlinkCancelledWaiters() {
 2             Node t = firstWaiter;
 3             Node trail = null;
 4             while (t != null) {
 5                 Node next = t.nextWaiter;
 6                 if (t.waitStatus != Node.CONDITION) {
 7                     t.nextWaiter = null;
 8                     if (trail == null)
 9                         firstWaiter = next;
10                     else
11                         trail.nextWaiter = next;
12                     if (next == null)
13                         lastWaiter = trail;
14                 }
15                 else
16                     trail = t;
17                 t = next;
18             }
19         }

doSignal方法的代码:

1         public final void signal() {//唤醒一个节点(线程)
2             if (!isHeldExclusively())
3                 throw new IllegalMonitorStateException();
4             Node first = firstWaiter;
5             if (first != null)
6                 doSignal(first);
7         }

doSignalAll方法的代码:

1         public final void signalAll() {//唤醒所有节点
2             if (!isHeldExclusively())
3                 throw new IllegalMonitorStateException();
4             Node first = firstWaiter;
5             if (first != null)
6                 doSignalAll(first);
7         }

awaitUninterruptibly方法的代码:

这个方法的作用就是将节点(线程)放入条件队列。

 1         public final void awaitUninterruptibly() {
 2             Node node = addConditionWaiter();//放入条件队列
 3             int savedState = fullyRelease(node);//释放资源
 4             boolean interrupted = false;
 5             while (!isOnSyncQueue(node)) {//当前节点是否在同步队列(在条件队列被唤醒后进入)
 6                 LockSupport.park(this);//如果不在,等待
 7                 if (Thread.interrupted())//检查是被中断还是被唤醒
 8                     interrupted = true;//如果是被中断设置interrupted,下面会设置中断标志
 9             }
10             if (acquireQueued(node, savedState) || interrupted)//尝试获取资源 设置中断标志
11                 selfInterrupt();
12         }

await方法的代码:

await方法和awaitUninterruptibly方法很相似,不同的地方是中断的处理。await方法的节点()线程如果是中断结束等待的,会根据当前中断的处理模式判断是抛出异常还是保留中断标志,不会再尝试获取资源。

 1         public final void await() throws InterruptedException {
 2             if (Thread.interrupted())
 3                 throw new InterruptedException();
 4             Node node = addConditionWaiter();
 5             int savedState = fullyRelease(node);
 6             int interruptMode = 0;
 7             while (!isOnSyncQueue(node)) {
 8                 LockSupport.park(this);
 9                 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)//如果是中断,break
10                     break;
11             }
12             if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
13                 interruptMode = REINTERRUPT;
14             if (node.nextWaiter != null) // clean up if cancelled
15                 unlinkCancelledWaiters();
16             if (interruptMode != 0)
17                 reportInterruptAfterWait(interruptMode);//抛出异常或保留中断标志
18         }

 ConditionObject的代码先说到这,下面说说ReentrantLock的代码。

2、ReentrantLock

ReentrantLock是独占模式的AQS,ReentrantLock有三个内部类,一个是抽象内部类。三个内部类为Sync、NonfairSync和FairSync。后面两个继承自前面一个。下面先说说这三个内部类。

Sync:

nonfairTryAcquire方法:

该方法的作用就是非公平地获取资源。

 1         final boolean nonfairTryAcquire(int acquires) {
 2             final Thread current = Thread.currentThread();
 3             int c = getState();
 4             if (c == 0) {//如果没有线程占有资源
 5                 if (compareAndSetState(0, acquires)) {//如果cas获取资源成功
 6                     setExclusiveOwnerThread(current);//将当前线程设置为独占资源的线程
 7                     return true;
 8                 }
 9             }
10             else if (current == getExclusiveOwnerThread()) {//如果当前线程是占有资源的线程
11                 int nextc = c + acquires;//增加state ReentrantLock里acquires都传1 state为n说明当前线程重入的次数为n - 1
12                 if (nextc < 0)//溢出
13                     throw new Error("Maximum lock count exceeded");
14                 setState(nextc);//设置state值
15                 return true;
16             }
17             return false;
18         }

tryRelease方法:

该方法的作用就是释放资源(锁),如果资源值(state)为0,则说明调用unlock的次数和调用lock的次数一样,锁可以释放供其它线程获取。

 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) {//如果c等于0 资源全部释放(也就是释放了锁)
 7                 free = true;
 8                 setExclusiveOwnerThread(null);
 9             }
10             setState(c);//设置state的值
11             return free;//返回是否释放了锁
12         }

newCondition方法:

该方法的作用就是创建新的条件队列。

1         final ConditionObject newCondition() {
2             return new ConditionObject();
3         }

NonfairSync:

lock方法:

非公平获取锁,每个线程获取锁时都会先cas试一下,如果成功了就直接获取了锁,不用再从入队出队开始。

1         final void lock() {
2             if (compareAndSetState(0, 1))
3                 setExclusiveOwnerThread(Thread.currentThread());
4             else
5                 acquire(1);//如果不成功还要排队继续
6         }

tryAcquire方法:

1         protected final boolean tryAcquire(int acquires) {
2             return nonfairTryAcquire(acquires);
3         }

FairSync:

lock方法:

公平获取锁,直接调用acquire,从入队出队开始。

        final void lock() {
            acquire(1);
        }

tryAcquire方法:

tryAcquire方法和nonfairTryAcquire方法类似,主要区别在于tryAcquire要求获取资源的节点(线程)必须是队首节点。

        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {//如果没有前驱节点(线程)且cas设置state成功,当前节点(线程)独占占有锁
                    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;
        }

说完了内部类,再看看几个提供的方法。

 1     public ReentrantLock() {
 2         sync = new NonfairSync();
 3     }
 4 
 5     public ReentrantLock(boolean fair) {
 6         sync = fair ? new FairSync() : new NonfairSync();
 7     }
 8 
 9     public void lock() {
10         sync.lock();
11     }
12 
13     public void lockInterruptibly() throws InterruptedException {
14         sync.acquireInterruptibly(1);
15     }
16 
17     public boolean tryLock() {
18         return sync.nonfairTryAcquire(1);
19     }
20 
21     public Condition newCondition() {
22         return sync.newCondition();
23     }

会发现这些方法基本上都是直接调用上面或之前说的那些方法。

posted @ 2018-06-20 15:45  Gouden  阅读(180)  评论(0编辑  收藏  举报