新闻资讯
AQS提供给锁实现者的API
1. 用于获取与设置共享资源的API:
- getState():获取当前同步状态
- setState():设置当前同步状态
- compareAndSetState(int expect, int update):使用CAS设置当前状态,该方法能够保证状态设置的原子性
2. 同步器可重写的方法:
这里AQS的设计者采用了模板设计模式将对同步状态的操作定义好过程,而将其中可以改变的过程交由每个具体的同步器(即锁)来实现,保证了每个同步器的特殊性; 上面讲的可能有点笼统,那我们不妨分析一下AQS定义的模板是什么?但在此之前,我们一定要牢记于心的是AQS是一个同步框架,即它所有的操作都是为了保证共享变量的安全!
- (以独占锁为例)在多线程的场景下,可能会有多个线程想要去访问共享变量,那么它们首先要做的是去看看自己有没有资格,即调用AQS的acquire()方法
public final void acquire(int arg) { if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
可以看到这个方法会调用tryAcquire()方法 和我们之前提到的 acquireQueued()方法,前者就是一个需要子类实现的模板方法,为什么一定要子类去实现,因为每种锁都应该自己去定义当前共享变量处在一个什么状态下时,请求线程可以获得共享资源的访问权(举个例子,独占锁时,只要当前共享资源有线程在访问,那么之后所有请求线程都不可以再获取到锁;而如果是共享锁,那么这个方法就要再共享资源状态可访问数允许的情况下让该请求线程获取到锁);而如果子类定义的tryAcquire() 认为当前线程获取不到锁,就应该调用acquireQueued() 方法去死循环+CAS尝试获取锁
- 然后线程对共享资源操作完了,那它就会去释放共享资源,就会调用AQS的release(int arg)方法
public final boolean release(int arg) { if (tryRelease(arg)) {
Node h = head; if (h != null && h.waitStatus != 0)
unparkSuccessor(h); return true;
} return false;
}
同acquire()一样,如何去判断是否可以释放对共享资源的访问权也是需要不同的锁自己去通过覆盖AQS中的tryRelease()方法去自己定义;
- 总结:所以模板方法即将框架搭好,但具有特殊性但又具有一致抽象的方法需要在子类中进行特殊化的实现;
回复列表