Java并发—通过ReentrantLock和Semaphore揭秘AQS独占模式和共享模式

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

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

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

1. ReentrantLock介绍

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

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

  • 公平锁:先对锁进行获取请求的线程一定先获得锁
  • 非公平锁

非公平锁的效率高于公平锁

非公平锁可能出现 线程饥饿问题——部分线程迟迟无法获得资源

ReentrantLock

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

2. ReentrantLock获得锁

2.1 非公平锁

ReentrantLock

2.2 公平锁

ReentrantLock

2.3 公平锁与非公平锁的不同

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

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

    tryAcquire()中,如果state为0,那么非公平锁不会关心节点在同步队列中的位置,直接尝试CAS修改state获得锁;但是非公平锁关心节点的位置,会检查是否有前继节点,如果有,就会放弃

上述2点保证了公平锁一定是——先对锁进行获取请求的线程一定先获得锁,而非公平锁不一定

3. ReentrantLock释放锁

公平锁释放锁与非公平锁释放锁采用同一个逻辑

ReentrantLock非公平锁释放锁

4. Semaphore介绍

Semaphore实现了AQS的共享模式

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

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

如果线程想要访问一个资源,必须先获得信号量减少,信号量为0时,线程无法访问资源,只能WATING等待信号量>0,

如果使用完资源,释放后,会补充信号量

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

Java并发—通过ReentrantLock和Semaphore揭秘AQS独占模式和共享模式_第1张图片

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共享模式获取锁的那一套

AQS共享模式获得锁

公平模式——FariSync中的 tryAcquireShared(int acquires)

.png)

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

Java并发—通过ReentrantLock和Semaphore揭秘AQS独占模式和共享模式_第2张图片

6.2 void release(int requires)

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

AQS共享模式释放锁

Sync实现了 tryReleaseShared(int releases)

Java并发—通过ReentrantLock和Semaphore揭秘AQS独占模式和共享模式_第3张图片

你可能感兴趣的:(java后端)