大家好,这里是淇妙小屋,一个分享技术,分享生存的博主
以下是我的主页,各个主页同步更新优质博客,创作不易,还请大家点波关注
掘金主页
后续会公布更多MySQL,Redis,并发,JVM,分布式等面试热点常识,以及Java学习路线,面试重点,职业规划,面经等相干博客
转载请表明出处!

本文将通过ReentrantLock和Semaphore带你看看AQS的独占模式和共享模式是怎么实现的

  • ReentrantLock实现了AQS的独占模式
  • Semaphore实现了AQS的共享模式

1. ReentrantLock介绍

可重入:任意线程取得锁后可能再次获取该锁而不会被锁阻塞

ReentrantLock实现了AQS的独占模式,是一个可重入锁,还分为 偏心锁非偏心锁

  • 偏心锁:先对锁进行获取申请的线程肯定先取得锁
  • 非偏心锁

非偏心锁的效率高于偏心锁

非偏心锁可能呈现 线程饥饿问题——局部线程迟迟无奈取得资源

ReentrantLock大多数办法的实现都是Sync及其子类来实现,ReentrantLock只是对外裸露了接口

2. ReentrantLock取得锁

2.1 非偏心锁

2.2 偏心锁

2.3 偏心锁与非偏心锁的不同

FairSync和NonfairSync的 lock() 和 tryAcquire() 逻辑不同

  1. 非偏心锁在lock()办法的开始就会尝试去通过CAS批改同步状态以取得锁,偏心锁不会
  2. 在自旋时,非偏心锁和偏心锁都会在前继节点为同步队列首节点时调用tryAcquire()尝试获取锁

    tryAcquire()中,如果state为0,那么非偏心锁不会关怀节点在同步队列中的地位,间接尝试CAS批改state取得锁;然而非偏心锁关怀节点的地位,会查看是否有前继节点,如果有,就会放弃

上述2点保障了偏心锁肯定是——先对锁进行获取申请的线程肯定先取得锁,而非偏心锁不肯定

3. ReentrantLock开释锁

偏心锁开释锁与非偏心锁开释锁采纳同一个逻辑

4. Semaphore介绍

Semaphore实现了AQS的共享模式

信号量,用来管制同时拜访特定资源的线程数目

初始化时指定信号量(permits)的数目(实质还是AQS的state)

如果线程想要拜访一个资源,必须先取得信号量缩小,信号量为0时,线程无法访问资源,只能WATING期待信号量>0,

如果应用完资源,开释后,会补充信号量

(之前的ReentrantLock中state=0示意锁可用,state不为0示意锁不可用,Semaphore这里state不为0示意锁可用,state为0示意锁不可用)

5. Semaphore办法介绍

//尝试获取一个信号量,如果信号量不为0,那么将信号量-1,返回//如果信号量为0,WAITING直到信号量不为0//可中断public void acquire() throws InterruptedException//尝试获取多个信号量,如果信号量足够,那么将信号量-permits,返回//如果信号量不够,WAITING直到信号量不为0//可中断 public void acquire(int permits) throws InterruptedException    //同acquire(),但不可中断public void acquireUninterruptibly()    //同acquire(int permits),但不可中断public void acquireUninterruptibly(int permits)//开释一个信号量public void release()    //开释permits个信号量public void release(int permits)

6. 办法详解

6.1 void acquire(int permits)

底层调用的还是AQS共享模式获取锁的那一套

偏心模式——FariSync中的 tryAcquireShared(int acquires)

.png)

非偏心模式——NonfairSync中的 tryAcquireShared(int acquires)调用Sync中的 nonfairTryAcquireShared(int acquires)

6.2 void release(int requires)

底层调用的还是AQS共享模式开释锁的那一套

Sync实现了 tryReleaseShared(int releases)