AQS原理
全称:AbstractQueueSynchronizer,是阻塞式锁和相关的同步器工具的框架 特点:
- 用state属性表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁
a. getState: 获取锁状态 b> setState:设置stare状态 c> compareAndSetState cas机制设置stare状态 - 提供了基于FIFO的等待队列,类似于Monitor的EntryList
- 条件变量来实现等待,唤醒机制,支持多个条件变量,类似于Monitor的WaitSet
子类主要实现这样一些方法(默认抛出UnsupportedOperationException)
- tryAcquire
- tryRelease
- tryAccquireShared
- tryReleaseShared
- isHeldExclusively
获取锁的姿势
if (!tryAcquire(arg)) {
}
释放锁的姿势
if (tryRelease(arg)){
}
手动实现一个不可重入锁
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
@Slf4j(topic = "c.TestAqs")
public class TestAqs {
public static void main(String[] args) {
MyLock lock = new MyLock();
new Thread(() -> {
lock.lock();;
try {
log.debug("loking...");
} finally {
log.debug("unloking...");
lock.unlock();
}
}, "t1").start();
new Thread(() -> {
lock.lock();;
try {
log.debug("locking...");
} finally {
log.debug("unloking...");
lock.unlock();
}
}, "t2").start();
}
}
class MyLock implements Lock{
class MySync extends AbstractQueuedSynchronizer{
@Override
protected boolean tryAcquire(int arg){
if(compareAndSetState(0, 1)){
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
@Override
protected boolean tryRelease(int arg){
setExclusiveOwnerThread(null);
setState(0);
return getState() == 0;
}
@Override
protected boolean isHeldExclusively(){
return getState() == 1;
}
public Condition newCondition(){
return new ConditionObject();
}
}
private MySync sync = new MySync();
@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(1);
}
@Override
public Condition newCondition() {
return sync.newCondition();
}
}
ReentrantLock原理
默认使用非公平锁
加锁解锁流程
加锁流程
lock方法调用的默认是同步器的lock方法 如果加锁成功则设置当前owner改为当前线程
反之 再次尝试加一次锁,仍然失败则尝试创建一个node节点对象并加入到等待队列中 即具体加锁失败流程为:
- CAS尝试将state由0改为1,结果失败
- 进入tryAcquire逻辑,这时stare已经是1,结果仍然失败
- 接下来进入addWaiter逻辑,构造node队列
a>. 图中黄色三角表示该node的waitStatus状态,其中0为默认争创状态 b> Node的创建是懒惰的 c> 其中第一个Node成为Dummy(哑元)或烧饼,用来占位,并不关联线程 当前线程进入acquireQueued逻辑 4. acquireQueued会在一个死循环中不断尝试获得锁,失败后进入park阻塞 5. 如果自己是紧邻着head,那么再次tryAcquire尝试获取锁,当然这是stare仍为1,失败 6. 进入shoudParkAfterFailedAcquire逻辑,将前驱node,即head的waitStarus改为-1,这次返回false
- shouldParkAfterFailedAcquire执行完毕回到acquireQueued,再次tryAcquire尝试获取锁,当然这是stare仍未1,失败
- 再次进入shouldParkAfterFailedAcquire时,这是因为前去node的waitStatus时-1,返回true
- 进入parkAndCheckInterrupt,Trhead-1 park(灰色表示)
再次有多个线程经历上述过程竞争失败,变成下图
释放锁的流程
Thread-0释放锁,进入tryReleas流程,如果成功
- 实则hiexclusiveOwnerThread为null
- state=0
当前队列部位null,并且head的waitStatus= -1,进入unparkSccessor流程 找到队列中离head最近的一个Node(没取消的),unpark恢复其运行,本例中即为Threa-1 回到Thread-1的accquireQueued流程 如果加锁成功(没有竞争),会设置
- exclusiveOwnerThread为Thread,stare=1
- head指向刚刚Thread-1所在node,该node清空Thread
- 原本的head因为从链表断开,而呗垃圾挥手
如果这时候有其他线程来竞争(非公平的表现),例如此时有Thread-4来了,则他两竞争锁 如果不巧又被Thread-4占了先 - Thread-4被设置为exclusiveOwnerThread,state=1
- Thread-1再次进入accquireQueued流程,获取锁失败,重新进入park阻塞
|