AQS原理
zhaolengquan Lv3

公平锁和非公平锁

先到临界区的线程比后到的线程一定更快的获取锁(公平锁)

公平锁就是把竞争的线程放入一个先进先出的队列中,持有锁的线程执行完了,唤醒队列的下一个线程获取锁就好了,

非公平锁是线程尝试获取锁,如果获取到锁就直接执行,获取不到锁,放入队列。

偏向锁 当前线程ID和markword存储的不相等,则cas尝试更换线程id,cas成功就获取到锁了,cas失败就升级为轻量级锁。

AQS内部维护了一个state状态变量,和一个先进先出的队列。

先进先出的队列存储的是Node节点,节点标识当前的状态,独占还是共享,以及前驱和后继节点信息。

ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore这些常用的实现类都是基于AQS实现的

外界调用lock方法时,首先CAS尝试获取锁,获取成功执行同步代码,获取失败则调用acquire方法,这是AQS的模板方法,acquire首先调用子类的tryAcquire方法,又回到了reentrantlock中,tryAcquire判断当前state是否为0,等于0说明没有线程持有锁,继续CAS获取锁,若获取成功,进入代码块,获取失败,判断当前线程是否持有锁,如果是持有的锁,更新state值,获取得到锁,(可重入锁的逻辑)。CAS失败&&不可重入的情况 回到tryAcquire方法执行入队列操作。节点入队列后判断前驱节点是不是头结点,如果是头结点又会用CAS尝试获取锁,如果是前驱节点是头结点并且CAS获取到了锁,则把当前节点设置为头结点,并将前驱节点置空(实际就是原有的头结点已经释放锁了),没获取到锁则判断前驱节点是否是SIGNAL,不是的话则找到合法的前驱节点并使用CAS将状态设置为SIGNAL。

AQS核心思想

如果被请求的资源空闲,则将当前线程设置为有效的工作线程,并将共享资源设置为锁定状态,如果被请求的共享资源被占用,那么就需要一套线程阻塞等待以及被唤醒时锁分配的机制,这个机制AQS使用CLH队列锁实现的,即将暂时获取不到锁的线程加入到队列中。

CLH队列是一个虚拟双向队列,虚拟双向队列即不存在队列实例,仅存在节点之间的关联关系。AQS是将每一条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁分配。

AQS就是基于CLH队列,用volatile修饰共享变量state,线程通过CAS去改变状态符,成功则获取锁成功,失败则进入等待队列,等待被唤醒

AQS的两种资源共享方式

Exclusive独占:只有一个线程能执行,Reentrantlock

Share共享:Semaphore,CountDownLatch,ReadWriteLock,CyclicBarrier

AQS底层使用了模板方法模式

同步器的设计是基于模板方法模式的,如果需要自定义同步器一般的方式是这样

使用者继承AbstractQueuedSynchronizer并重写指定的方法,自定义同步器在实现的时候只需要实现共享资源state的获取和释放方式即可。

Reentrantlock为例:state初始化为0,表示未锁定状态,A线程Lock时,会调用tryAcquire独占锁,并将state+1,之后其他线程再想tryAcquire时就会失效,直到A线程unlock到state=0为止,其他线程才有机会获取该锁。A释放锁之前,自己可以重复获取此锁(state累加),这就是可重入的概念

 Comments