AQS
全稱:AbstractQueuedSynchronizer,譯爲:抽象隊列同步器。
AQS是很多併發工具類的基礎,可以說是實現整個java.util.concurrent併發包的半壁江山。
public abstract class AbstractQueuedSynchronizer
extends AbstractOwnableSynchronizer
implements java.io.Serializable
AbstractQueuedSynchronizer是一個抽象類,本身不能實例化。
它用到了“模板方法設計模式”,定義了一個模板骨架,子類需要實現部分流程方法才能使用。
重要方法
-
int getState()
獲取同步狀態。 -
void setState()
設置同步狀態。 -
boolean compareAndSetState(int expect, int update)
基於CAS操作來設置同步狀態。
setState和compareAndSetState
這兩個方法的區別是:一個是非原子的,一個是原子的。
什麼時候用setState?
釋放鎖時使用setState,因爲只有獲取鎖的線程才能調用該方法,不存在併發問題,所以無需使用CAS操作。
什麼時候用compareAndSetState?
加鎖時使用compareAndSetState,因爲鎖競爭時是併發的,設置同步狀態操作必須是CAS的,否則可能多個線程同時加鎖成功。
子類重寫方法
AQS的功能可以分爲兩類:獨佔式與共享式。
獨佔式:同一時刻最多隻允許一個線程獲得鎖,
共享式:同一時刻允許多個線程獲得鎖,
獨佔式
-
boolean tryAcquire(int arg)
獨佔式嘗試獲取鎖。 -
boolean tryRelease(int arg)
獨佔式嘗試釋放鎖。 -
boolean isHeldExclusively()
判斷當前線程是否獲取獨佔鎖。
共享式
-
boolean tryAcquireShared(int arg)
共享式嘗試獲取鎖。 -
boolean tryReleaseShared(int arg)
共享式嘗試釋放鎖。
根據自己要實現的鎖類型,重寫對應的方法即可。
模板方法
AQS定義了一組模板方法,子類不允許重寫,可直接調用。
獨佔式
-
void acquire(int arg)
獨佔式獲取鎖。 -
void acquireInterruptibly(int arg)
獨佔式獲取鎖,支持中斷。 -
boolean tryAcquireNanos(int arg,long nanos)
獨佔式嘗試獲取鎖,支持超時。 -
boolean release(int arg)
獨佔式釋放鎖。
共享式
-
void acquireShared(int arg)
共享式獲取鎖。 -
void acquireSharedInterruptibly(int arg)
共享式獲取鎖,支持中斷。 -
boolean tryAcquireSharedNanos(int arg,long nanos)
共享式嘗試獲取鎖,支持超時。 -
boolean releaseShared(int arg)
共享式釋放鎖。
自定義鎖實例
MyLock
/**
* @Author: 潘
* @Date: 2019/11/23 16:18
* @Description: 基於Lock和AQS實現自定義鎖
*/
public class MyLock implements Lock {
//AQS實例
private final Sync sync = new Sync();
/**
* 繼承AQS 實現獨佔鎖
* state 0無鎖 1有鎖
*/
static class Sync extends AbstractQueuedSynchronizer{
/**
* 重寫tryAcquire
* 獲取鎖成功和失敗均輸出提示文字
* @param arg
* @return
*/
@Override
protected boolean tryAcquire(int arg) {
if (compareAndSetState(0, arg)) {
//設置獨佔鎖線程爲當前線程
setExclusiveOwnerThread(Thread.currentThread());
System.out.println(Thread.currentThread().getName()+"鎖競爭成功");
return true;
}
System.out.println(Thread.currentThread().getName()+"鎖競爭失敗");
return false;
}
//嘗試釋放鎖
@Override
protected boolean tryRelease(int arg) {
setState(arg);
setExclusiveOwnerThread(null);
return true;
}
@Override
protected boolean isHeldExclusively() {
return super.isHeldExclusively();
}
}
@Override
public void lock() {
sync.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return sync.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
@Override
public void unlock() {
sync.release(0);
}
@Override
public Condition newCondition() {
return sync.new ConditionObject();
}
}
測試
class MyLockDemo{
private MyLock lock = new MyLock();
void test(){
lock.lock();
SleepUtil.sleep(1000);
System.out.println(Thread.currentThread().getName());
lock.unlock();
}
public static void main(String[] args) {
MyLockDemo demo = new MyLockDemo();
for (int i = 0; i < 3; i++) {
new Thread(()->{
demo.test();
}).start();
}
}
}
輸出如下:
Thread-0鎖競爭成功
Thread-2鎖競爭失敗
Thread-1鎖競爭失敗
Thread-2鎖競爭失敗
Thread-2鎖競爭失敗
Thread-0
Thread-2鎖競爭成功
Thread-2
Thread-1鎖競爭成功
Thread-1