AQS(AbstractQueuedSynchronizer)

AQS(AbstractQueuedSynchronizer)

整理不易,如果文章对您有益,麻烦给点个赞,收藏一下,防止走丢

AQS是线程队列同步器,用来构建锁或者其它同步器组件的重要级基础框架及整个JUC体系的基石,通过内置的FIFO队列来完成资源获取线程的排队工作,并通过一个int类型变量表示持有锁的状态。

对于ReentranLock等,是面向锁的使用者,而AQS是面向锁的实现者。

如果共享资源被占用,就需要一定的阻塞等待唤醒机制来保证锁的分配。这个机制主要用的是CLH队列的变体实现的,将暂时获取不到锁的线程加入到队列中,这个队列就是AQS的抽象表现。它将请求共享资源的线程封装成队列的节点(Node),通过CAS、自旋以及LockSupport.park()的方式,维护state变量的状态,使并发达到同步的控制效果。

以ReentranLock的加解锁作为切入点认识AQS

在ReentranLock类内部有AQS的实现子类,并按照公平和非公平锁,分成两个实现子类。

大致结构如下

public class ReentrantLock{

	private final Sync sync;

	// AQS子类
	abstract static class Sync extends AbstractQueuedSynchronizer {
	}

	// 非公平锁具体实现子类
	static final class NonfairSync extends Sync {
	}

	// 公平锁具体实现子类
	static final class FairSync extends Sync {
	}
}

接下来,以加解锁两个过程来探寻一下AQS的作用机制。

加锁

ReentranLock的加锁,对于使用者来说,非常简单。

ReentrantLock lock = new ReentrantLock();
lock.lock();

其中lock方法:

public void lock() {
    sync.lock();
}

加锁方法就是直接调用AQS的lock方法,然后再根据ReentranLock采用的公平锁或非公平锁提供具体实现。ReentranLock默认是非公平锁。

非公平锁Lock()
final void lock() {
    // 尝试将锁的状态,由0改变为1,其实就是一直尝试抢占锁的动作
    if (compareAndSetState(0, 1))
        // 如果成功修改锁状态,说明抢占成功,将当前线程设置成执行线程
        setExclusiveOwnerThread(Thread.currentThread());
    else
        // 获得锁
        acquire(1);
}
公平锁Lock()
final void lock() {
    // 获得锁
    acquire(1);
}

从上面两种锁策略的lock代码中,可以看到非公平锁,一开始就尝试自行抢占。

acquire(1)方法
public final void acquire(int arg) {
    // 产生获取锁
    if (!tryAcquire(arg) &&
        // 入队
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

tryAcquire(arg)又重新尝试获取锁,并根据公平锁和非公平锁进行些许不同的操作。

非公平锁tryAcquire(arg)
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;
}
公平锁tryAcquire(arg)
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;
}

公平锁tryAcquire(arg)与非公平锁tryAcquire(arg)的唯一区别在于公平锁多了一个hasQueuedPredecessors() 方法。

addWaiter(Node.EXCLUSIVE)
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;
}

进行将线程入队,如果队列不为空,则添加到队尾,如果队列为空,则调用enq方法创建初始节点并入队。

enq(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;
            }
        }
    }
}
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
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;
            }
            // 判断是否应该被park(休眠) 并进行休眠
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

shouldParkAfterFailedAcquire(p, node)

判断是否在抢占失败后进行park

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

parkAndCheckInterrupt()

park当前线程

private final boolean parkAndCheckInterrupt() {
    LockSupport.park(this);
    return Thread.interrupted();
}

解锁

ReentranLock的解锁,对于使用者来说,也非常简单。

lock.unlock();

其中unlock()方法

public void unlock() {
    sync.release(1);
}
release(int arg)

释放锁

public final boolean release(int arg) {
    // 尝试释放
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}
tryRelease(arg)

尝试释放

protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    // 如果当前线程不是执行线程,抛出异常
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值