J.U.C
AQS 原理
- 概述:全称是 AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架
- 特点:
- 用 state 属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁
- getState - 获取 state 状态
- setState - 设置 state 状态
- compareAndSetState - cas 机制设置 state 状态
- 独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源
- 提供了基于 FIFO 的等待队列,类似于 Monitor 的 EntryList
- 条件变量来实现等待、唤醒机制,支持多个条件变量,类似于 Monitor 的 WaitSet
- 用 state 属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁
子类主要实现这样一些方法(默认抛出 UnsupportedOperationException)
- tryAcquire
- tryRelease
- tryAcquireShared
- tryReleaseShared
- isHeldExclusively
实现一个不可重入锁
@Slf4j(topic = "c.TestAqs")
public class TestAqs {
public static void main(String[] args) {
MyLock myLock = new MyLock();
new Thread(()->{
log.debug("t1尝试加锁。。。。");
myLock.lock();
try {
log.debug("t1得到锁。。。。");
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
myLock.unlock();
log.debug("t1解锁。。。。");
}
}).start();
new Thread(()->{
log.debug("t2尝试加锁。。。。");
myLock.lock();
myLock.lock();
log.debug("t2尝试第二次加锁。。。。");
try {
log.debug("t2得到锁。。。。");
}finally {
myLock.unlock();
log.debug("t2解锁。。。。");
}
}).start();
}
}
/**
* 实现一个简单的不可重入锁
*/
class MyLock implements Lock {
/**
* 创建一个同步器类,实现了大部分下列的方法,我们只要补充几个
* 在这里要做一个独占锁,需要重写下面几个方法
*/
class MySycn extends AbstractQueuedSynchronizer{
/**
* 尝试获取锁
* @param arg
* @return
*/
@Override
protected boolean tryAcquire(int arg) {
//用CAS的方式保证加锁操作是原子性的。
if (compareAndSetState(0,1)){
//加上了锁
//将当前线程设置为Owner线程,即获取锁
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
/**
* 尝试释放锁
* @param arg
* @return
*/
@Override
protected boolean tryRelease(int arg) {
//将Owner线程置为null
setExclusiveOwnerThread(null);
//将状态值改为0,因为State是Volatile修饰的,有别的线程可能会读取State
setState(0);
return true;
}
/**
* 是否持用独占锁
* @return
*/
@Override
protected boolean isHeldExclusively() {
return getState() == 1;
}
/**
* 返回一个新的条件变量
*/
public Condition newCondition(){
return new ConditionObject();
}
//至此同步器类完成
}
private MySycn sycn = new MySycn();
/**
* 加锁,不成功就进入等待队列等待
*/
@Override
public void lock() {
sycn.acquire(1);
}
/**
* 加锁,但是可以打断
* @throws InterruptedException
*/
@Override
public void lockInterruptibly() throws InterruptedException {
sycn.acquireInterruptibly(1);
}
/**
* 尝试加锁,只进行一次
* @return
*/
@Override
public boolean