并发编程-Lock AQS

ReentrantLock

实现JUC包下面的Lock,基于AQS实现,需手动加锁解锁。

从源码入手查看ReentrantLock的工作流程:
以公平锁举例:

public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

protected final boolean tryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
        	//hasQueuedPredecessors=>Queries whether any threads have been waiting to acquire longer than the current thread.
        	//如果CLH队列中有在等待的节点,且当前线程不是下一个node的线程,则返回true
            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;
    }
}

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);
    }
}

static void selfInterrupt() {
    Thread.currentThread().interrupt();
}

流程:

  1. 当一个线程尝试获取锁时,会先去获取state的值,如果值为0,表示这个资源此时未被其它线程持有。则进行CAS操作设置新的state,并将当前锁的线程持有者设置为当前线程。如果state的值不为0且当前锁的持有线程为当前线程,则设置新的state,此操作也间接证明了ReentrantLock是可重入锁
  2. 获取锁失败时,将当前线程加入CLH队列中。
  3. 如果获取锁失败,且加入CLH队列中,则线程中断。

AbstractQueuedSynchronizer

一个用于实现依赖于先进先出(FIFO)等待队列的阻塞锁和相关的同步器框架。

Java.concurrent.util当中同步器的实现如Lock,Latch,Barrier等,都是基于AQS框架实现。

一般通过定义内部类Sync继承AQS,将同步器所有调用都映射到Sync对应的方法。

比如ReentrantLock中,就定义了一个Sync内部类且同步器的调用都是映射到Sync的方法中。

Doug LeaAbstractQueuedSynchronizer中做了大量注释说明。以下为部分重要节选:

Provides a framework for implementing blocking locks and related synchronizers (semaphores, events, etc) that rely on first-in-first-out (FIFO) wait queues. This class is designed to be a useful basis for most kinds of synchronizers that rely on a single atomic int value to represent state. Subclasses must define the protected methods that change this state, and which define what that state means in terms of this object being acquired or released. Given these, the other methods in this class carry out all queuing and blocking mechanics. Subclasses can maintain other state fields, but only the atomically updated int value manipulated using methods getState, setState and compareAndSetState is tracked with respect to synchronization.

This class supports either or both a default exclusive mode and a shared mode. When acquired in exclusive mode, attempted acquires by other threads cannot succeed. Shared mode acquires by multiple threads may (but need not) succeed. This class does not "understand" these differences except in the mechanical sense that when a shared mode acquire succeeds, the next waiting thread (if one exists) must also determine whether it can acquire as well. Threads waiting in the different modes share the same FIFO queue. Usually, implementation subclasses support only one of these modes, but both can come into play for example in a ReadWriteLock. Subclasses that support only exclusive or only shared modes need not define the methods supporting the unused mode.

This class defines a nested AbstractQueuedSynchronizer.ConditionObject class that can be used as a Condition implementation by subclasses supporting exclusive mode for which method isHeldExclusively reports whether synchronization is exclusively held with respect to the current thread, method release invoked with the current getState value fully releases this object, and acquire, given this saved state value, eventually restores this object to its previous acquired state. No AbstractQueuedSynchronizer method otherwise creates such a condition, so if this constraint cannot be met, do not use it. The behavior of AbstractQueuedSynchronizer.ConditionObject depends of course on the semantics of its synchronizer implementation.


Usage
To use this class as the basis of a synchronizer, redefine the following methods, as applicable, by inspecting and/or modifying the synchronization state using getState, setState and/or compareAndSetState:
tryAcquire
tryRelease
tryAcquireShared
tryReleaseShared
isHeldExclusively

AQS特性

  • 阻塞等待队列
  • 共享/独占
  • 公平/非公平
  • 可重入
  • 允许中断

AQS属性

state

同步状态,上锁是状态值+1,释放锁时状态值-1。使用CAS修改state的值,以保证state的原子性。

/**
* The synchronization state.
*/
private volatile int state;
exclusiveOwnerThread

继承自java.util.concurrent.locks.AbstractOwnableSynchronizer的属性,独占锁的线程所有者。

/**
* The current owner of exclusive mode synchronization.
*/
private transient Thread exclusiveOwnerThread;
等待队列

AbstractQueuedSynchronizer中有个内部类Node,构造了等待队列(双向队列) 和条件队列(单向队列,prev和next为null,)。
当线程获取锁失败时,会进入到CLH队列(等待队列,是一个双向链表指针队列)中。

等待队列是CLH锁定队列的变体。CLH是一种基于单向链表的高性能、公平的自旋锁。 CLH锁通常用于自旋锁。 相反,我们将它们用于阻塞同步器,但使用相同的基本策略,将有关线程的某些控制信息保存在其节点的前身中。

以下是源码对CLH的注释说明。

The wait queue is a variant of a "CLH" (Craig, Landin, and Hagersten) lock queue. CLH locks are normally used for spinlocks. We instead use them for blocking synchronizers, but use the same basic tactic of holding some of the control information about a thread in the predecessor of its node. 

AbstractQueuedSynchronizer.Node属性说明:

/** Marker to indicate a node is waiting in shared mode 标记节点为共享模式*/	
static final Node SHARED = new Node();
/** Marker to indicate a node is waiting in exclusive mode 标记节点为独占模式*/
static final Node EXCLUSIVE = null;

/** waitStatus value to indicate thread has cancelled */
//在等待队列中的线程超时或被中断,需要从等待队列中取消等待。
static final int CANCELLED =  1;

/** waitStatus value to indicate successor's thread needs unparking */
//后续线程处于等待状态时,若当前节点如果释放了同步状态或被取消,通知后续节点运行
static final int SIGNAL    = -1;

/** waitStatus value to indicate thread is waiting on condition */
//该节点当前在条件队列中。在传输之前,它不会用作同步队列节点。
//当其它线程对Condition调用signal()方法后,节点从等待队列转移到同步队列中,并加入到同步状态的获取中。
//如果node在条件队列中,只能是独占模式。
static final int CONDITION = -2;

/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
//下一次同步共享状态应该无条件传播下去
static final int PROPAGATE = -3;

//当前节点的状态值(1->CANCELLED,0->默认值,-1->SIGNAL,-2->CONDITION,-3->PROPAGATE ),使用CAS进行修改,volatile 保证可见性。
volatile int waitStatus;

//前驱节点,当前节点加入等待队列时被设置
volatile Node prev;

//后继节点
volatile Node next;
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值