概述
稍微对并发源码了解的朋友都知道,很多并发工具如ReentrantLock、CountdownLatch的实现都是依赖AQS, 全称
AbstractQueuedSynchronizer。
AQS是一种提供了原子式管理同步状态、阻塞和唤醒线程功能以及队列模型的简单框架。一般来说,同步工具实现锁的控制分为独占锁和共享锁,而AQS提供了对这两种模式的支持。
独占锁: 也叫排他锁,即锁只能由一个线程获取,若一个线程获取了锁,则其他想要获取锁的线程只能等待,直到锁被释放。比如说写锁,对于写操作,每次只能由一个线程进行,若多个线程同时进行写操作,将很可能出现线程安全问题,比如jdk中的ReentrantLock。
共享锁: 锁可以由多个线程同时获取,锁被获取一次,则锁的计数器+1。比较典型的就是读锁,读操作并不会产生副作用,所以可以允许多个线程同时对数据进行读操作,而不会有线程安全问题,当然,前提是这个过程中没有线程在进行写操作,比如ReadWriteLock和CountdownLatch。
本文重点讲解下AQS对独占锁模式的支持。
自定义独占锁例子
首先我们自定义一个非常简单的独占锁同步器demo, 来了解下AQS的使用。
publicclassExclusiveLockimplementsLock{
// 同步器,继承自AQSprivatestaticclassSyncextendsAbstractQueuedSynchronizer{
// 重写获取锁的方式@OverrideprotectedbooleantryAcquire(int acquires){
assert acquires == 1;
// cas的方式抢锁if(compareAndSetState(0, 1)) {
// 设置抢占锁的线程为当前线程
setExclusiveOwnerThread(Thread.currentThread());
returntrue;
}
returnfalse;
}
@OverrideprotectedbooleantryRelease(int releases){
assert releases == 1;
if (getState() == 0) {
thrownew IllegalMonitorStateException();
};
//设置抢占锁的线程为null
setExclusiveOwnerThread(null);
// 释放锁
setState(0);
returntrue;
}
}
privatefinal Sync sync = new Sync();
@Overridepublicvoidlock(){
sync.acquire(1);
}
@Overridepublicvoidunlock(){
sync.release(1);
}
@OverridepublicvoidlockInterruptibly()throws InterruptedException {
sync.acquireInterruptibly(1);
}
@OverridepublicbooleantryLock(){
return sync.tryAcquire(1);
}
@OverridepublicbooleantryLock(long time, TimeUnit unit)throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(time));
}
@Overridepublic Condition newCondition(){
returnnull;
}
}
这里是一个不可重入独占锁类,它使用值0表示未锁定状态,使用值1表示锁定状态。
验证:
publicstaticvoidmain(String[] args) throws InterruptedException {
ExclusiveLock exclusiveLock = new ExclusiveLock();
new Thread(() -> {
try {
exclusiveLock.lock();
System.out.println("thread1 get lock");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
exclusiveLock.unlock();
System.out.println("thread1 release lock");
}
}).start();
new Thread(() -> {
try {
exclusiveLock.lock();
System.out.println("thread2 get lock");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
exclusiveLock.unlock();
System.out.println("thread2 release lock");
}
}).start();
Thread.currentThread().join();
}
这样一个很简单的独占锁同步器就实现