沭阳网站定制,网络设计图纸是什么,贵阳哪些公司建网站,wordpress 父页面1-概述 AQS全称是 AbstractQueuedSynchronizer#xff0c;是阻塞式锁和相关的同步器工具的框架。同步器的设计是基于模板方法模式的#xff0c;也就是说#xff0c;使用者需要继承同步器并重写指定的方法#xff0c;随后将同步器组合在自定义同步组件的实现中#xff0c;并…1-概述 AQS全称是 AbstractQueuedSynchronizer是阻塞式锁和相关的同步器工具的框架。同步器的设计是基于模板方法模式的也就是说使用者需要继承同步器并重写指定的方法随后将同步器组合在自定义同步组件的实现中并调用同步器提供的模板方法而这些模板方法将会调用使用者重写的方法。
1.1-主要特点
1用 state 属性来表示资源的状态分独占模式和共享模式子类需要定义如何维护这个状态控制如何获取锁和释放锁。其中state的具体定义由子类开发者去设计。 getState - 获取 state 状态; setState - 设置 state 状态; compareAndSetState - cas 机制设置 state 状态; 独占模式是只有一个线程能够访问资源而共享模式可以允许多个线程访问资源。
2提供了基于 FIFO 的等待队列类似于 Monitor 的 EntryList 3条件变量来实现等待、唤醒机制支持多个条件变量类似于 Monitor 的 WaitSet。
1.2-AQS中重要的方法描述
同步器可重写的方法 方法名称描述protected boolean tryAcquire(int arg)独占式获取同步状态实现该方法需要查询当前状态并判断同步状态是否符合预期然后再进行 CAS 设置同步状态protected boolean tryRelease(int arg)独占式释放同步状态等待获取同步状态的线程将有机会获取同步状态protected int tryAcquireShared(int arg)共享式获取同步状态返回大于等于0的值表示获取成功反之获取失败protected boolean tryReleaseShared(int arg)共享式释放同步状态protected boolean isHeldExclusively()当前同步器是否在独占模式下被线程占用一般该方法表示是否被当前线程所独占 实现自定义同步组件时将会调用同步器提供的模板方法这些(部分)模板方法与描述如下
方法名称描述void acquire(int arg)独占式获取同步状态如果当前线程获取同步状态成功则由该方法返回否则将会进入同步队列等待该方法将会调用重写的 tryAcquire(intarg)法void acquireInterruptibly(int arg)与acquire(int arg)相同但是该方法响应中断当前线程未获取到同步状态而进入同步队列中如果当前线程被中断则该方法会抛出InterruptedException 并返回boolean tryAcquireNanos(int arglong nanos)在acquireInterruptibly(int arg)基础上增加了超时限制如果当前线程在超时时间内没有获取到同步状态那么将会返回 false如果获取到了返回 truevoid acquireShared(int arg)共享式的获取同步状态如果当前线程未获取到同步状态将会进入同步队列等待与独占式获取的主要区别是在同一时刻可以有多个线程获取到同步状态void acquireSharedInterruptibly(int arg)与acquireShared(int arg)相同该方法响应中断boolean tryAcquireSharedNanos(intarg, long nanos)在acquireSharedInterruptibly(intarg)基础上增加了超时限制boolean release(int arg)独占式的释放同步状态该方法会在释放同步状态之后将同步队列中第个节点包含的线程唤醒boolean releaseShared(int arg)共享式的释放同步状态CollectionThread getQueuedThreads)获取等待在同步队列上的线程集合 同步器提供的模板方法基本上分为3 类:独占式获取与释放同步状态、共享式获取与释放同步状态和查询同步队列中的等待线程情况。自定义同步组件将使用同步器提供的模板方法来实现自己的同步语义。
1.3-设计思想
state设计state 使用 volatile 配合 cas 保证其修改时的原子性 阻塞恢复设计park unpark 来实现线程的暂停和恢复 队列设计使用了 FIFO 先入先出队列并不支持优先级队列借鉴了 CLH 队列它是一种单向无锁队列。 2-基于AQS实现自定义锁
2.1-自定义实现不可重入排他锁
基于AQS可以快速实现自定义锁下面就来实现一个 排他锁不可重入。
public class MyLock1 implements Lock {static MySync1 mySync1new MySync1();//尝试 加锁不成功就进入等待队列Overridepublic void lock() {mySync1.acquire(1);}//尝试不成功进入等待队列可打断Overridepublic void lockInterruptibly() throws InterruptedException {mySync1.acquireInterruptibly(1);}//尝试一次不成功返回不进入队列Overridepublic boolean tryLock() {return mySync1.tryAcquire(1);}//尝试不成功进入等待队列有时限Overridepublic boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return mySync1.tryAcquireNanos(1,unit.toNanos(time));}Overridepublic void unlock() {mySync1.release(1);}Overridepublic Condition newCondition() {return mySync1.newCondition();}//独占锁实现tryAcquiretryReleaseisHeldExclusivelystatic class MySync1 extends AbstractQueuedSynchronizer{Overrideprotected boolean tryAcquire(int acquire) {//我们可以设计state 为0 时表示 没有线程占用锁if(acquire1){if(compareAndSetState(0,1)){setExclusiveOwnerThread(Thread.currentThread());//state字段是volatile 可以防止指令重排序 所以将线程设置 代码放置 在setState之前setState(1);return true;}}return false;}Overrideprotected boolean tryRelease(int acquire) {//能够进入这个方法表示当前线程肯定已经获取到锁了if(acquire1){if(getState()0){throw new IllegalMonitorStateException();}setExclusiveOwnerThread(null);setState(0);return true;}return false;}protected Condition newCondition() {return new ConditionObject();}Overrideprotected boolean isHeldExclusively() {return getState()1;}}
}测试排他性 MyLock1 myLock1new MyLock1();new Thread(()-{myLock1.lock();try {log.info(t1-lock);TimeUnit.SECONDS.sleep(1);}catch (Exception e){log.error(t1-error);}finally {myLock1.unlock();log.info(t1-unlock);}},t1).start();new Thread(()-{myLock1.lock();try {log.info(t2-lock);}catch (Exception e){log.error(t2-error);}finally {myLock1.unlock();log.info(t2-unlock);}},t2).start();
控制台输出
15:36:17.590 [t1] INFO com.ycmy2023.aqs.demo01.TestDemo - t1-lock 15:36:18.595 [t2] INFO com.ycmy2023.aqs.demo01.TestDemo - t2-lock 15:36:18.595 [t2] INFO com.ycmy2023.aqs.demo01.TestDemo - t2-unlock 15:36:18.595 [t1] INFO com.ycmy2023.aqs.demo01.TestDemo - t1-unlock
由此可见必须当线程1持有锁释放的时候线程2才能获取到锁。 测试不可重入 MyLock1 myLock1new MyLock1();new Thread(()-{myLock1.lock();log.info(t1-获取锁1);myLock1.lock();log.info(t1-获取锁2);try {log.info(t1-lock);TimeUnit.SECONDS.sleep(1);}catch (Exception e){log.error(t1-error);}finally {myLock1.unlock();log.info(t1-unlock);}},t1).start();
控制台输出
15:38:42.028 [t1] INFO com.ycmy2023.aqs.demo01.TestDemo - t1-获取锁1
一直阻塞在第一个日志输出的地方不会输出第二个日志说明同一个线程获取到锁不能再次加锁。 2.2-自定义实现共享锁 设计一个同步工具:该工具在同一时刻只允许至多两个线程同时访问超过两个线程的访问将被阻塞。
分析需求
1确定访问模式。能够在同一时刻支持多个线程的访问这显然是共享式访问因此需要使用同步器提供的acquireShared(int args)方法等和Shared 相关的方法这就要求必须重写 tryAcquireShared(int args)方法和 tryReleaseShared(int args)方法这样才能保证同步器的共享式同步状态的获取与释放方法得以执行。
2定义资源数。在同一时刻允许至多两个线程的同时访问表明同步资源数为2这样可以设置初始状态 status 为2当一个线进行获取state 减1该线程释放则 state加1状态的合法范围为 0、1和2。其中0表示当前已经有两个线获取了同步资源此时再有其他线程对同步状态进行获取该线程只能被阻塞。在同步状态变更时需要使用compareAndSet(int expect,int update)方法做原子性保障。 public class MySharedLock implements Lock {private static MySync2 syncnew MySync2(2);Overridepublic void lock() {sync.acquireShared(1);}Overridepublic void lockInterruptibly() throws InterruptedException {}Overridepublic boolean tryLock() {return false;}Overridepublic boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return false;}Overridepublic void unlock() {sync.releaseShared(1);}Overridepublic Condition newCondition() {return null;}private static class MySync2 extends AbstractQueuedSynchronizer{MySync2(int count){setState(count);}Overrideprotected int tryAcquireShared(int reduceCount) {for(;;){int currentgetState();int newCountcurrent-reduceCount;if(newCount 0 || compareAndSetState(current,newCount)){return newCount;}}}Overrideprotected boolean tryReleaseShared(int returnCount) {for(;;){int currentgetState();int newCountcurrentreturnCount;if(compareAndSetState(current,newCount)){return true;}}}}
}测试开发写的锁 MySharedLock locknew MySharedLock();new Thread(()-{lock.lock();log.info(t1-获取锁1);try {log.info(t1-lock);TimeUnit.SECONDS.sleep(5);}catch (Exception e){log.error(t1-error);}finally {lock.unlock();log.info(t1-unlock);}},t1).start();new Thread(()-{lock.lock();log.info(t2-获取锁1);try {log.info(t2-lock);TimeUnit.SECONDS.sleep(8);}catch (Exception e){log.error(t2-error);}finally {lock.unlock();log.info(t2-unlock);}},t2).start();new Thread(()-{lock.lock();log.info(t3-获取锁1);try {log.info(t3-lock);TimeUnit.SECONDS.sleep(4);}catch (Exception e){log.error(t3-error);}finally {lock.unlock();log.info(t3-unlock);}},t3).start();控制台输出
16:02:50.705 [t2] INFO com.ycmy2023.aqs.demo02.TestDemo02 - t2-获取锁1 16:02:50.705 [t1] INFO com.ycmy2023.aqs.demo02.TestDemo02 - t1-获取锁1 16:02:50.708 [t2] INFO com.ycmy2023.aqs.demo02.TestDemo02 - t2-lock 16:02:50.708 [t1] INFO com.ycmy2023.aqs.demo02.TestDemo02 - t1-lock 16:02:55.709 [t1] INFO com.ycmy2023.aqs.demo02.TestDemo02 - t1-unlock 16:02:55.709 [t3] INFO com.ycmy2023.aqs.demo02.TestDemo02 - t3-获取锁1 16:02:55.709 [t3] INFO com.ycmy2023.aqs.demo02.TestDemo02 - t3-lock 16:02:58.717 [t2] INFO com.ycmy2023.aqs.demo02.TestDemo02 - t2-unlock 16:02:59.716 [t3] INFO com.ycmy2023.aqs.demo02.TestDemo02 - t3-unlock