AbstractQueuedSynchronizer 为 java.util.concurrent.locks 包下的一个抽象类,简称 AQS抽象队列同步器)。

并发包(JUC)中的 ReentrantLock、Semaphore、ReentrantReadWriteLock、SynchronousQueue、FutureTask 等,底层都是基于 AQS 来实现的。

 

一、使用

1.AQS 采用了模板模式

自定义同步器时需要重写下面几个方法。

// 该线程是否正在独占资源(是否在独占模式下被线程占用)。只有用到 condition 才需要去实现它。
boolean isHeldExclusively();

// 独占方式。尝试获取资源,成功则返回 true,失败则返回 false。
boolean tryAcquire(int arg);

// 独占方式。尝试释放资源,成功则返回 true,失败则返回 false。
// 成功后,等待中的其他线程此时将有机会获取到资源。
boolean tryRelease(int arg);

// 共享方式。尝试获取资源。负数表示失败;0 表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
int tryAcquireShared(int arg);

// 共享方式。尝试释放资源,成功则返回 true,失败则返回 false。
boolean tryReleaseShared(int);

默认每个方法都抛出 UnsupportedOperationException。 这些方法的实现必须是内部线程安全的,并且通常应该简短而不是阻塞。

AQS 类中的其它方法都是 final 修饰,无法被其它类使用。

2.AQS 对资源的共享方式

一般自定义同步器,要么是独占(tryAcquire-tryRelease)方式,要么是共享(tryAcquireShared-tryReleaseShared)方式。(AQS 也支持同时实现,如 ReentrantReadWriteLock)

  • Exclusive(独占):只有一个线程能执行,如 ReentrantLock。独占又可分为公平锁和非公平锁:

    • 公平锁:按照线程在队列中的排队顺序,先到者先拿到锁

    • 非公平锁:当线程要获取锁时,无视队列顺序直接去抢锁,谁抢到就是谁的

  • Share(共享):多个线程可同时执行,如 Semaphore、CountDownLatCh、 CyclicBarrier、ReadWriteLock。

3.自定义同步器(独占式)

Java AbstractQueuedSynchronizer(AQS)
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class MyMutex {
    private final Sync sync = new Sync();

    // 当前状态为 0 时获取锁,然后进行 CAS 设置同步状态
    // 未获取到当前线程则会进入同步队列等待
    public void lock() {
        sync.acquire(1);
    }

    // 释放锁,将状态设置为 0
    public void unlock() {
        sync.release(1);
    }

    // 是否处于被当前线程占有状态
    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    private static final class Sync extends AbstractQueuedSynchronizer {
        @Override
        protected boolean tryAcquire(int arg) {
            // 首先判断状态是否=0,如果状态=0,就将 status 设置为 1
            if (compareAndSetState(0, 1)) {
                // 将当前线程赋值给独占模式的 onwer
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            // 判断当前是获得资源的线程
            if (Thread.currentThread() != getExclusiveOwnerThread() || getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            // 没有线程拥有这个锁
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        @Override
        protected boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread() && getState() == 1;
        }
    }
}
View Code

相关文章: