多线程在并发过程中发生竞争时,其实都满足以下语义:
当共有状态(state)满足某种条件时,线程执行;若不满足,则排队(queue)等待(park),直到被唤醒(unpark);
或者换一种表述:
当线程获取锁时,则继续执行;否则排队(queue)等待(park),直到被唤醒(unpark);
AQS实际上就是对上述基本语义的包装实现。
在不同的上下文中,满足状态的条件可能是不一样的,因此要由子类去实现;而排队等待包括等待后的唤醒行为应该都是相同的,所以这一部分已经由AQS实现完毕。
AQS中定义了state变量来表示共有状态,子类需要从该变量获取共有状态当前的值。
private volatile int state;
protected final int getState() { return state; }
protected final void setState(int newState) { state = newState; }
需要子类去实现的方法重要的有如下几个,比如第一个方法,若满足状态(获得了锁),则要返回true,否则返回false。
//独占锁
protected boolean tryAcquire(int arg) { throw new UnsupportedOperationException(); }
protected boolean tryRelease(int arg) { throw new UnsupportedOperationException(); }
//共享锁
protected int tryAcquireShared(int arg) { throw new UnsupportedOperationException(); }
protected boolean tryReleaseShared(int arg) { throw new UnsupportedOperationException(); }
下表为各个类对state值的判断
Class | state | 锁类型 | 说明 |
---|---|---|---|
ReentrantLock | 0 或 非0 | 独占锁 | state可以理解为锁的唯一一把钥匙,若为0,说明钥匙没人用,当前线程获取钥匙开了锁,其他线程都等待;否则若exclusiveThread==currentThread,则重入;否则阻塞 |
CountDownLatch | 是否大于0 | 共享锁 | state可以理解为倒计时,若为0,说明倒计时结束,waiting()的线程可以执行(可能有多个线程同时竞争执行) |
Semaphore | 是否大于0 | 共享锁 | 此时state可以理解为通行证,若大于0,说明还有证书,当前线程可以执行;否则阻塞 |
ReentrantReadWriteLock.WriteLock | 0 或 非0 | 独占锁 | 获取writeLock后,readLock无法再获取 |
ReentrantReadWriteLock.ReadLock | 是否大于0 | 共享锁 | 获取reakLock后,writeLock无法再获取 |