AQS和ReentrantLock

一、AQS

AQS结构
AbstractQueuedSynchronizer是一个抽象同步框架,主体由等待队列和共享变量state构成。AQS包括两种队列:
等待队列和条件队列。

支持特性包括:

  • 1.阻塞等待队列
  • 2.共享/独占
  • 3.公平/非公平
  • 4.可重入
  • 5.允许中断

1.1 等待队列和条件队列

1.1.1 等待队列

主要用于维护获取锁失败的线程。
等待队列有prev和next两个属性,是一个基于双向链表的队列。

1.1.2 条件队列

调用await()方法时会释放锁,然后线程会加入条件队列,调用signal唤醒时,会把条件队列中的节点移动到等待队列中。
条件队列通过nextWaiter连接,是一个单向链表。

1.2 源码分析

1.2.1 基本属性

// 头结点
private transient volatile Node head;
// 尾节点
private transient volatile Node tail;
// 共享变量
private volatile int state;

通过state判断锁状态以及实现可重入锁。

1.2.2 内部类节点

static final class Node {
    // 共享和独占标识
    static final Node SHARED = new Node();
    static final Node EXCLUSIVE = null;
    // 节点状态
    volatile int waitStatus;
    // 前置和后置节点
    volatile Node prev;
    volatile Node next;
    
    Node nextWaiter;
}

根据头尾节点可以看出,等待队列是一个基于双向链表的队列。节点存在共享和独占两种状态。

1.2.3 waitStatus状态

// 表示线程获取锁的请求已取消
static final int CANCELLED =  1;
// 表示线程已准备好等待资源释放
static final int SIGNAL    = -1;
// 表示节点在等待队列中,等待唤醒
static final int CONDITION = -2;
// 在共享情况下才会使用
static final int PROPAGATE = -3;

二、ReentrantLock

ReentrantLock是基于AQS的一种应用实现。它是可重入的互斥锁,类似Synchronized,但比Synchronized更加灵活。
ReentrantLock基本结构

2.1 源码分析

2.1.1 非公平锁加锁过程

// 加锁方法
public void lock() {
    sync.acquire(1);
}

// 获取锁及入队
public final void acquire(int arg) {
    // 先尝试获取锁,再进行入队操作
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

// 获取非公平锁
final boolean nonfairTryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    // 判断state状态
    if (c == 0) {
        // 尝试设置state
        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;
}

// 设置尾节点
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    Node pred = tail;
    // 尾结点不为空则直接加入新节点
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    // 尾结点为空将节点插入队列
    enq(node);
    return node;
}

// 节点加入队列,必要时初始化队列
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;
            }
        }
    }
}

// 入队
final boolean acquireQueued(final Node node, int arg) {
    boolean interrupted = false;
    try {
        for (;;) {
            // 获取上一节点
            final Node p = node.predecessor();
            // 判断上一节点是否是头节点,并尝试获取一次锁
            if (p == head && tryAcquire(arg)) {
                // 设置为头节点
                setHead(node);
                p.next = null; // help GC
                return interrupted;
            }
            if (shouldParkAfterFailedAcquire(p, node))
                // 判断并为线程设置中断状态
                interrupted |= parkAndCheckInterrupt();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

// 设置waitStatus,保持SIGNAL状态
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    // 获取前一节点的状态
    int ws = pred.waitStatus;
    if (ws == Node.SIGNAL)
        // 前一节点为SIGNAL状态,可以安全调用park()方法
        return true;
    if (ws > 0) {
        // 如果前一节点为CANCELLED状态,则说明前一节点由于某些情况中断而取消,需要跳过这些节点
        do {
            node.prev = pred = pred.prev;
        } while (pred.waitStatus > 0);
        pred.next = node;
    } else {
        // 通过CAS设置状态为SIGNAL
        pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
    }
    return false;
}

2.1.2 非公平锁解锁过程

public final boolean release(int arg) {
    if (tryRelease(arg)) {
        // 解锁后获取头结点
        Node h = head;
        // 头节点不为空且节点不在等待状态时,使用unpark唤醒线程
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

protected final boolean tryRelease(int releases) {
    // state-1
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    // 若state为0,则锁已释放
    if (c == 0) {
        free = true;
        // 取消独占锁的线程
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值