什么是AQS
AQS(AbstractQueuedSynchronizer),中文名抽象队列同步器
AQS定义了一套多线程访问共享资源的同步器框架,主要用来自定义锁和同步器
AQS原理
AQS 核心思想:
- 如果被请求的共享资源空闲,则将当前请求资源的线程设置为有效的工作线程,并且将共享资源设置为锁定状态。
- 如果被请求的共享资源被占用,将暂时获取不到锁的线程加入到阻塞队列中,等待被唤醒和锁的分配
实现核心思想的的队列:CLH队列
CLH队列是一个虚拟的双向队列,AQS 是将每条请求共享资源的线程封装成一个 CLH 锁队列的一个结点(Node)来实现锁的分配。
共享资源用 volatile 关键词修饰,保证线程间的可见性
/** * The synchronization state. */ private volatile int state;
0状态表示空闲,1状态或以上表示不空闲
共享资源(state)的访问方式有三种:
- getState() 获得共享资源状态
- setState() 设置共享资源状态
- compareAndSetState() 更改共享资源状态(底层unsafe类)
源代码如下
/** * Returns the current value of synchronization state. * This operation has memory semantics of a {@code volatile} read. * @return current state value */ protected final int getState() { return state; } /** * Sets the value of synchronization state. * This operation has memory semantics of a {@code volatile} write. * @param newState the new state value */ protected final void setState(int newState) { state = newState; } /** * Atomically sets synchronization state to the given updated * value if the current state value equals the expected value. * This operation has memory semantics of a {@code volatile} read * and write. * * @param expect the expected value * @param update the new value * @return {@code true} if successful. False return indicates that the actual * value was not equal to the expected value. */ protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }
利用AQS实现自定义锁
一:首先创建一个类实现Lock接口,它有6个方法需要实现
- lock():加锁(不成功进入阻塞队列等待)
- lockInterruptibly():是否加锁可打断
- tryLock()://加锁(不成功不会进入阻塞队列等待,可以去做其他事情)
- tryLock(long time,TimeUnit unit):加锁(规定时间内未获得则放弃加锁)
- unlock():释放锁
- newCondition():创建条件变量
二:创建一个内部类,继承AbstractQueuedSynchronizer
可以根据需求重写具体方法,总共有5种方法
- isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。
- tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。
- tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
- tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
- tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false。
三:我需要自定义一个独占锁,不可重入,具有变量条件的锁
分析
- 独占锁:AQS同步器中需要重写独占方式的获取资源tryAcquire(int)和释放资源tryRelease(int)方法
- 不可重入:AQS同步器需要实现isHeldExclusively():
- 具有条件变量:AQS同步器中 return new ConditionObject();
具体代码如下
//自定义锁(不可重入)(独占锁)(条件变量) class MyLock implements Lock{ //内部类,AQS同步器类 class MySync extends AbstractQueuedSynchronizer{ @Override protected boolean tryAcquire(int arg) { if (compareAndSetState(0,1)){ System.out.println("获得锁成功"); //加上了锁,并设置owner为当前线程 setExclusiveOwnerThread(Thread.currentThread()); return true; } System.out.println("获得锁失败"); return false; } @Override protected boolean tryRelease(int arg) { setExclusiveOwnerThread(null); setState(0); return true; } @Override protected boolean isHeldExclusively() { return getState() == 1; } public Condition newCondition(){ return new ConditionObject(); } } private MySync mySync = new MySync(); @Override //加锁(不成功进入阻塞队列等待) public void lock() { mySync.acquire(1); } @Override //加锁可打断 public void lockInterruptibly() throws InterruptedException { mySync.acquireInterruptibly(1); } @Override //加锁(不成功不会进入阻塞队列等待,可以去做其他事情) public boolean tryLock() { return mySync.tryAcquire(1); } @Override //尝试加锁 带时间 public boolean tryLock(long time, TimeUnit unit) throws InterruptedException { return mySync.tryAcquireNanos(1,unit.toNanos(time)); } @Override //释放锁 public void unlock() { mySync.release(1); } @Override //创建条件变量 public Condition newCondition() { return mySync.newCondition(); } }
到此这篇关于Java利用AQS实现自定义锁的文章就介绍到这了,更多相关Java AQS实现自定义锁内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!