这段时间自己学了下并发编程,然后发现提供的并发工具全部都和AQS有关。无论是Lock还是信号量,计数器等,都逃不过与AQS的联系。写这篇博客的初衷其实是自己想写一些并发工具类的文章,包括countdownlatch或者信号量之类的,但是它们底层都涉及到了AQS,所以先写这个AQS,一来是为了让自己更深刻的理解,二来是让大家阅读的时候有个参考。话不多说,开始今天的AQS
AQS(AbstractQueuedSynchronizer)抽象的队列同步器。简单来说AQS就是一个用来构建锁或者其他同步组件的一个框架,就是一个工具类。(它本身是个抽象类)
AQS的主要使用方式就是继承,通过继承AQS来重写一些满足自己逻辑的方法——这就是模板设计模式
在AQS中设置了一个int类型的state,用它来表示是否获得了锁之类的情况。
下面先来看看对应的一些方法
下面是能够重写的方法(如果你需要自己设计一些锁或者同步工具类,那么一定要选择自己适合的方法去写自己对应的业务规则):
我们现在自己手写一个简单的独占锁,且不可重入
/**
* 独占锁,不可重入
*/
public class SelfLock implements Lock {
private static class Syn extends AbstractQueuedSynchronizer{
/**
* 返回一个Condition,每个condition都包含了一个condition队列
*/
Condition newCondition() {
return new ConditionObject();
}
@Override
protected boolean tryAcquire(int arg) {
if(compareAndSetState(0,1)){
setExclusiveOwnerThread(Thread.currentThread());//设置当前线程为占有锁的线程
System.out.println("当前线程 "+getExclusiveOwnerThread().getName()+" 获取锁");
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg){
//判断是否同一个操作
if(getExclusiveOwnerThread().equals(Thread.currentThread())){
setExclusiveOwnerThread(null);
setState(0);
System.out.println("当前线程 "+Thread.currentThread().getName()+" 释放锁");
return ture;
//不需要使用cas操作,因为获得了锁的才能释放锁
//compareAndSetState(1,0);
}
return false;
}
/**
* 判断是否占用
* @return
*/
@Override
protected boolean isHeldExclusively() {
return (getState()==1);
}
}
private Syn syn = new Syn();
@Override
public void lock() {
syn.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
syn.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return syn.tryAcquire(1);
}
@Override
public boolean tryLock(long time, TimeUnit timeUnit) throws InterruptedException {
return syn.tryAcquireNanos(1,timeUnit.toNanos(time));
}
@Override
public void unlock() {
syn.tryRelease(1);
}
@Override
public Condition newCondition() {
return syn.newCondition();
}
}
因为是非公平锁,所以我们继承AQS重写了三个方法,tryAcquire(尝试获取锁),tryRelease(尝试释放锁)isHeldExclusively(是否占有锁);<