转载

聊聊你对 AQS 的了解

AQS是一个并发包的基础组件,用来实现各种锁,各种同步组件的。

包含了state变量、加锁线程、等待队列等并发中的核心组件。

AQS全称是队列同步器AbstractQueuedSynchronizer,是用来构建锁或者其他同步组件的基础框架。

它使用了一个int成员变量表示同步状态,默认情况下是0

/**

  • The synchronization state.

    */

    private volatile int state;

通过内置的FIFO队列来完成资源获取线程的排队工作。

同步器的主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理同步状态,在抽象方法的实现过程中免不了要对同步状态进行更改。

这时就需要使用同步器提供的3个方法(getState()、setState(int newState)和compareAndSetState(int expect,int update))来进行操作,因为它们能够保证状态的改变是安全的。

/**获取当前同步状态
protected final int getState() {
        return state;
    }
/**
设置当前同步状态
 */
protected final void setState(int newState) {
    state = newState;
}
```java
/**
 使用CAS设置当前状态,该方法能够保证状态设置的原子性。
 */
protected final boolean compareAndSetState(int expect, int update) {
    // See below for intrinsics setup to support this
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

同步器既可以支持独占式地获取同步状态,也可以支持共享式地获取同步状态,这样就可以方便实现不同类型的同步组件(ReentrantLock、ReentrantReadWriteLock和CountDownLatch)。

独占锁就是在同一时刻只能有一个线程获取到锁,而其他获取锁的线程只能处于同步队列中等待,只有获取锁的线程释放了锁,后继的线程才能够获取锁。

示例代码
class Mutex implements Lock {
// 静态内部类,自定义同步器
private static class Sync extends AbstractQueuedSynchronizer {
// 是否处于占用状态
protected boolean isHeldExclusively() {
return getState() == 1;
}
// 当状态为0的时候获取锁
public boolean tryAcquire(int acquires) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
// 释放锁,将状态设置为0
protected boolean tryRelease(int releases) {
if (getState() == 0) throw new
IllegalMonitorStateException();
setExclusiveOwnerThread(null);
setState(0);
return true;
}
// 返回一个Condition,每个condition都包含了一个condition队列
Condition newCondition() { return new ConditionObject(); }
}
// 仅需要将操作代理到Sync上即可
private final Sync sync = new Sync();
public void lock() { sync.acquire(1); }
public boolean tryLock() { return sync.tryAcquire(1); }
public void unlock() { sync.release(1); }
public Condition newCondition() { return sync.newCondition(); }
public boolean isLocked() { return sync.isHeldExclusively(); }
public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}

在tryAcquire(int acquires)方法中,如果经过CAS设置成功(同步状态设置为1),则代表获

取了同步状态,而在tryRelease(int releases)方法中只是将同步状态重置为0。

可重入锁ReentrantLock和AQS的关系

顾名思义,就是支持重进入的锁,它表示该锁能够支持一个线程对资源的重复加锁。

ReentrantLock内部也是包含了一个AQS对象。

abstract static class Sync extends AbstractQueuedSynchronizer {
...
}

从这里理解等待队列,当线程1已经加完锁后,另外的线程再想加锁就将一个队列中等待锁的释放。

除此之外,该锁的还支持获取锁时的公平和非公平性选择。

聊聊你对 AQS 的了解

原文  https://mp.weixin.qq.com/s/jYuL7DPVYPP5UpcOSTXctg
正文到此结束
Loading...