Java多线程--AQS

ReentrantLock和AQS的关系

首先我们来看看,如果用java并发包下的ReentrantLock来加锁和释放锁,是个什么样的:

1 ReentrantLock reentrantLock = new ReentrantLock();
2 reentrantLock.lock();
3 //业务代码
4 reentrantLock.unlock();

 上面那段代码就是搞一个Lock对象,然后加锁和释放锁。那么,这个跟AQS有啥关系?关系大了去了,因为java并发包下很多API都是基于AQS来实现的加锁和释放锁等功能的,AQS是java并发包的基础类。上一部分源码:

 1 public class ReentrantLock implements Lock, java.io.Serializable {
 2     private static final long serialVersionUID = 7373984872572414699L;
 3     /** Synchronizer providing all implementation mechanics */
 4     private final Sync sync;
 5 
 6     /**
 7      * Base of synchronization control for this lock. Subclassed
 8      * into fair and nonfair versions below. Uses AQS state to
 9      * represent the number of holds on the lock.
10      */
11     abstract static class Sync extends AbstractQueuedSynchronizer {
12         private static final long serialVersionUID = -5179523762034025860L;
13 
14         /**
15          * Performs {@link Lock#lock}. The main reason for subclassing
16          * is to allow fast path for nonfair version.
17          */
18         abstract void lock();
19 
20         /**
21          * Performs non-fair tryLock.  tryAcquire is implemented in
22          * subclasses, but both need nonfair try for trylock method.
23          */
24         final boolean nonfairTryAcquire(int acquires) {
25             final Thread current = Thread.currentThread();
26             int c = getState();
27             if (c == 0) {
28                 if (compareAndSetState(0, acquires)) {
29                     setExclusiveOwnerThread(current);
30                     return true;
31                 }
32             }
33             else if (current == getExclusiveOwnerThread()) {
34                 int nextc = c + acquires;
35                 if (nextc < 0) // overflow
36                     throw new Error("Maximum lock count exceeded");
37                 setState(nextc);
38                 return true;
39             }
40             return false;
41         }
42 
43         protected final boolean tryRelease(int releases) {
44             int c = getState() - releases;
45             if (Thread.currentThread() != getExclusiveOwnerThread())
46                 throw new IllegalMonitorStateException();
47             boolean free = false;
48             if (c == 0) {
49                 free = true;
50                 setExclusiveOwnerThread(null);
51             }
52             setState(c);
53             return free;
54         }
55 
56         protected final boolean isHeldExclusively() {
57             // While we must in general read state before owner,
58             // we don't need to do so to check if current thread is owner
59             return getExclusiveOwnerThread() == Thread.currentThread();
60         }
61 
62         final ConditionObject newCondition() {
63             return new ConditionObject();
64         }
65 
66         // Methods relayed from outer class
67 
68         final Thread getOwner() {
69             return getState() == 0 ? null : getExclusiveOwnerThread();
70         }
71 
72         final int getHoldCount() {
73             return isHeldExclusively() ? getState() : 0;
74         }
75 
76         final boolean isLocked() {
77             return getState() != 0;
78         }
79 
80         /**
81          * Reconstitutes the instance from a stream (that is, deserializes it).
82          */
83         private void readObject(java.io.ObjectInputStream s)
84             throws java.io.IOException, ClassNotFoundException {
85             s.defaultReadObject();
86             setState(0); // reset to unlocked state
87         }
88     }
89 }

说白了,ReentrantLock内部包含了一个AQS对象,也就是AbstractQueuedSynchronizer类型的对象。这个AQS对象就是ReentrantLock可以实现加锁和释放锁的关键性的核心组件。

ReentrantLock加锁和释放锁的底层原理

现在如果有一个线程过来尝试用ReentrantLock的lock()方法进行加锁,会发生什么事情呢?

 1 public abstract class AbstractQueuedSynchronizer
 2     extends AbstractOwnableSynchronizer
 3     implements java.io.Serializable {
 4 
 5    /**
 6     * The thread that enqueued this node.  Initialized on
 7     * construction and nulled out after use.
 8     */
 9     volatile Thread thread;
10 
11     /**
12      * The synchronization state.
13      */
14     private volatile int state;
15 
16 }

这个AQS对象内部有一个核心的变量叫做state,是int类型的,代表了加锁的状态。初始状态下,这个state的值是0。另外,这个AQS内部还有一个关键变量,用来记录当前加锁的是哪个线程,初始化状态下,这个变量是null。接着线程1跑过来调用ReentrantLock的lock()方法尝试进行加锁,这个加锁的过程,直接就是用CAS操作将state值从0变为1。如果之前没人加过锁,那么state的值肯定是0,此时线程1就可以加锁成功。一旦线程1加锁成功了之后,就可以设置当前加锁线程是自己。

AQS就是并发包里的一个核心组件,里面有state变量、加锁线程变量等核心的东西,维护了加锁状态。ReentrantLock这种东西只是一个外层的API,内核中的锁机制实现都是依赖AQS组件的。这个ReentrantLock之所以用Reentrant打头,意思就是他是一个可重入锁。意思就是你可以对一个ReentrantLock对象多次执行lock()加锁和unlock()释放锁,也就是可以对一个锁加多次,叫做可重入加锁。大家看明白了那个state变量之后,就知道了如何进行可重入加锁!其实每次线程1可重入加锁一次,会判断一下当前加锁线程就是自己,那么他自己就可以可重入多次加锁,每次加锁就是把state的值给累加1,别的没啥变化,实现原理如下:

 1 public class ReentrantLock implements Lock, java.io.Serializable {
 2     /**
 3      * Sync object for non-fair locks
 4      */
 5     static final class NonfairSync extends Sync {
 6         private static final long serialVersionUID = 7316153563782823691L;
 7 
 8         /**
 9          * Performs lock.  Try immediate barge, backing up to normal
10          * acquire on failure.
11          */
12         final void lock() {
13             if (compareAndSetState(0, 1))
14                 setExclusiveOwnerThread(Thread.currentThread());
15             else
16                 acquire(1);
17         }
18 
19         protected final boolean tryAcquire(int acquires) {
20             return nonfairTryAcquire(acquires);
21         }
22     }
23 }
24 
25 public abstract class AbstractQueuedSynchronizer
26     extends AbstractOwnableSynchronizer
27     implements java.io.Serializable {
28 
29     /**
30      * Acquires in exclusive mode, ignoring interrupts.  Implemented
31      * by invoking at least once {@link #tryAcquire},
32      * returning on success.  Otherwise the thread is queued, possibly
33      * repeatedly blocking and unblocking, invoking {@link
34      * #tryAcquire} until success.  This method can be used
35      * to implement method {@link Lock#lock}.
36      *
37      * @param arg the acquire argument.  This value is conveyed to
38      *        {@link #tryAcquire} but is otherwise uninterpreted and
39      *        can represent anything you like.
40      */
41     public final void acquire(int arg) {
42         if (!tryAcquire(arg) &&
43             acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
44             selfInterrupt();
45     }
46 
47 }

接着,如果线程1加锁了之后,线程2跑过来加锁会怎么样呢?我们来看看锁的互斥是如何实现的,线程2跑过来一下看到state的值不是0,所以CAS操作将state从0变为1的过程会失败,因为state的值当前为1,说明已经有人加锁了!接着线程2会看一下,是不是自己之前加的锁啊?当然不是了,“加锁线程”这个变量明确记录了是线程1占用了这个锁,所以线程2此时就是加锁失败。接着,线程2会将自己放入AQS中的一个等待队列,因为自己尝试加锁失败了,此时就要将自己放入队列中来等待,等待线程1释放锁之后,自己就可以重新尝试加锁了,所以大家可以看到,AQS是如此的核心。AQS内部还有一个等待队列,专门放那些加锁失败的线程。

 1 /**
 2  * Condition implementation for a {@link
 3  * AbstractQueuedSynchronizer} serving as the basis of a {@link
 4  * Lock} implementation.
 5  *
 6  * <p>Method documentation for this class describes mechanics,
 7  * not behavioral specifications from the point of view of Lock
 8  * and Condition users. Exported versions of this class will in
 9  * general need to be accompanied by documentation describing
10  * condition semantics that rely on those of the associated
11  * {@code AbstractQueuedSynchronizer}.
12  *
13  * <p>This class is Serializable, but all fields are transient,
14  * so deserialized conditions have no waiters.
15  */
16 public class ConditionObject implements Condition, java.io.Serializable {
17         private static final long serialVersionUID = 1173984872572414699L;
18         /** First node of condition queue. */
19         private transient Node firstWaiter;
20         /** Last node of condition queue. */
21         private transient Node lastWaiter;
22 
23         /**
24          * Creates a new {@code ConditionObject} instance.
25          */
26         public ConditionObject() { }
27 
28         // Internal methods
29 
30         /**
31          * Adds a new waiter to wait queue.
32          * @return its new wait node
33          */
34         private Node addConditionWaiter() {
35             Node t = lastWaiter;
36             // If lastWaiter is cancelled, clean out.
37             if (t != null && t.waitStatus != Node.CONDITION) {
38                 unlinkCancelledWaiters();
39                 t = lastWaiter;
40             }
41             Node node = new Node(Thread.currentThread(), Node.CONDITION);
42             if (t == null)
43                 firstWaiter = node;
44             else
45                 t.nextWaiter = node;
46             lastWaiter = node;
47             return node;
48         }
49 }

接着,线程1在执行完自己的业务逻辑代码之后,就会释放锁,他释放锁的过程非常的简单,就是将AQS内的state变量的值递减1,如果state值为0,则彻底释放锁,会将“加锁线程”变量也设置为null!

 1 public class ReentrantLock implements Lock, java.io.Serializable {  
 2     /**
 3      * Attempts to release this lock.
 4      *
 5      * <p>If the current thread is the holder of this lock then the hold
 6      * count is decremented.  If the hold count is now zero then the lock
 7      * is released.  If the current thread is not the holder of this
 8      * lock then {@link IllegalMonitorStateException} is thrown.
 9      *
10      * @throws IllegalMonitorStateException if the current thread does not
11      *         hold this lock
12      */
13     public void unlock() {
14         sync.release(1);
15     }
16 }
17 
18 public abstract class AbstractQueuedSynchronizer
19     extends AbstractOwnableSynchronizer
20     implements java.io.Serializable {
21      public final boolean release(int arg) {
22         if (tryRelease(arg)) {
23             Node h = head;
24             if (h != null && h.waitStatus != 0)
25                 unparkSuccessor(h);
26             return true;
27         }
28         return false;
29     }
30 }

接下来,会从等待队列的队头唤醒线程2重新尝试加锁。好!线程2现在就重新尝试加锁,这时还是用CAS操作将state从0变为1,此时就会成功,成功之后代表加锁成功,就会将state设置为1。此外,还要把“加锁线程”设置为线程2自己,同时线程2自己就从等待队列中出队了。

其实一句话总结:AQS就是一个并发包的基础组件,用来实现各种锁,各种同步组件的。它包含了state变量、加锁线程、等待队列等并发中的核心组件。

猜你喜欢

转载自www.cnblogs.com/ding-dang/p/11072290.html