ReentrantLock
,Semaphore
,其他的诸如ReentrantReadWriteLock
,SynchronousQueue
,FutureTask
等等皆是基于AQS的。当然,我们自己也能利用AQS非常轻松容易地构造出符合我们自己需求的同步器。AQS核心思想是:
CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列(虚拟的双向队列即不存在队列实例,仅存在结点之间的关联关系)。AQS是将每条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node)来实现锁的分配。
AQS 全称是 AbstractQueuedSynchronizer,是阻塞式锁和相关的同步器工具的框架
用 state
属性来表示资源的状态(分独占模式和共享模式),子类需要定义如何维护这个状态,控制如何获取锁和释放锁 ;
getState
- 获取 state
状态setState
- 设置 state
状态compareAndSetState
- cas 机制设置 state
状态独占模式是只有一个线程能够访问资源,而共享模式可以允许多个线程访问资源
提供了基于 FIFO 的等待队列,类似于 Monitor
的 EntryList
条件变量来实现等待、唤醒机制,支持多个条件变量,类似于 Monitor 的 WaitSet
子类主要实现这样一些方法 :
默认抛出 UnsupportedOperationException
独占锁是不可重入锁 , 已经获得锁的话, 再次请求获得锁会导致死锁.
/** * 独占锁 同步器类 */ class MySync extends AbstractQueuedSynchronizer { @Override protected boolean tryAcquire(int arg) { // 尝试获取锁, 通过状态字段state设置锁 if (compareAndSetState(0, 1)) { // 加锁, 并设置 owner 为当前线程 setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } @Override protected boolean tryRelease(int arg) { setExclusiveOwnerThread(null); // 释放的时候, 因为已经获取独占锁了, 只有当前线程有锁, 所以直接设置状态即可 // state 是volatile修饰, 在此之前对类属性的修改, 都会同步到主存, 并且 setState(0); return true; } /** * 是否持有独占锁 * * @return */ @Override protected boolean isHeldExclusively() { return this.getState() == 1; } public Condition newCondition() { return new ConditionObject(); } }
我们通过集成 AbstractQueuedSynchronizer
类来实现独占锁, AbstractQueuedSynchronizer 是使用 state 字段用于控制获取锁
package cn.knightzz.juc.aqs.custom; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.AbstractQueuedSynchronizer; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; /** * @author 王天赐 * @title: MyAqsLock * @projectName hm-juc-codes * @description: 自定义不可重入锁 * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a> * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a> * @create: 2022-09-05 14:27 */ @SuppressWarnings("all") public class MyAqsLock implements Lock { /** * 独占锁 同步器类 */ class MySync extends AbstractQueuedSynchronizer { @Override protected boolean tryAcquire(int arg) { // 尝试获取锁, 通过状态字段state设置锁 if (compareAndSetState(0, 1)) { // 加锁, 并设置 owner 为当前线程 setExclusiveOwnerThread(Thread.currentThread()); return true; } return false; } @Override protected boolean tryRelease(int arg) { setExclusiveOwnerThread(null); // 释放的时候, 因为已经获取独占锁了, 只有当前线程有锁, 所以直接设置状态即可 // state 是volatile修饰, 在此之前对类属性的修改, 都会同步到主存, 并且 setState(0); return true; } /** * 是否持有独占锁 * * @return */ @Override protected boolean isHeldExclusively() { return this.getState() == 1; } public Condition newCondition() { return new ConditionObject(); } } private MySync sync = new MySync(); /** * 加锁, 加锁不成功会进入等待队列 */ @Override public void lock() { sync.acquire(1); } /** * 加锁, 但是可以打断 * * @throws InterruptedException */ @Override public void lockInterruptibly() throws InterruptedException { sync.tryAcquire(1); } /** * 尝试加锁 (尝试一次) * * @return */ @Override public boolean tryLock() { return sync.tryAcquire(1); } /** * 尝试加锁, 带超时 * * @param time the maximum time to wait for the lock * @param unit the time unit of the {@code time} argument * @return * @throws InterruptedException */ @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(); } }
简单介绍下 :
package cn.knightzz.juc.aqs.custom; import lombok.extern.slf4j.Slf4j; import static java.lang.Thread.sleep; /** * @author 王天赐 * @title: MyAqsLockTest * @projectName hm-juc-codes * @description: 测试自定义锁 * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a> * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a> * @create: 2022-09-06 21:47 */ @SuppressWarnings("all") @Slf4j(topic = "c.MyAqsLockTest") public class MyAqsLockTest { public static void main(String[] args) { MyAqsLock lock = new MyAqsLock(); new Thread(() -> { lock.lock(); try { log.debug("locking..."); sleep(1); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { log.debug("unlocking..."); lock.unlock(); } },"t1").start(); new Thread(() -> { lock.lock(); try { log.debug("locking..."); } finally { log.debug("unlocking..."); lock.unlock(); } },"t2").start(); } }
本文作者:王天赐
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!