java---ReentrantLock

「这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战

ReentrantLock介绍

java多线程中可以使用synchronized关键字来实现线程间同步互斥,但在jdk1.5中新增加了ReentrantLock类也能实现同样的效果。

ReentrantLock:表示重入锁,它是唯一一个实现了Lock接口的类。重入锁指的是 线程在获得锁之后,再次获取该锁不需要阻塞,而是直接关联一次计数器增加重入次;

Lock常用方法

4b19ee7b203703f8c723e477cbcb956.png

ReentrantLock.lock() 这个是reentrantLock获取锁的入口

   public void lock() {
        sync.lock();
    }
复制代码

adc1fb3a70b461a8c41b7d763560784.jpg

sync实际上是一个抽象的静态内部类,它继承了AQS来实现重入锁的逻辑,我们前面说过AQS是一个同步队列,它能够实现线程的阻塞以及唤醒,但它并不具备 业务功能,所以在不同的同步场景中,会继承AQS来实现对应场景的功能 Sync有两个具体的实现类,

什么是AQS?

AQS即AbstractQueuedSynchronizer,是一个用于构建锁和同步器的框架。它能降低构建锁和同步器的工作量,还可以避免处理多个位置上发生的竞争问题。在基于AQS构建的同步器中,只可能在一个时刻发生阻塞,从而降低上下文切换的开销,并提高吞吐量

AQS支持独占锁(exclusive)和共享锁(share)两种模式。

  • 独占锁:只能被一个线程获取到(Reentrantlock)
  • 共享锁:可以被多个线程同时获取(CountDownLatch,ReadWriteLock).

分别是:

NofairSync:非公平锁,可以存在抢占锁的功能,也就是说不管当前队列上是否存在其他 线程等待,新线程都有机会抢占锁

FailSync:公平锁,所有线程严格按照FIFO来获取锁

公平锁示例

谁等的时间最长,谁就先获取锁

public class ReentrantLockTest {
​
    static Lock lock = new ReentrantLock(true);
​
    public static void main(String[] args) throws InterruptedException {
​
        for(int i=0;i<5;i++){
            new Thread(new ThreadDemo(i)).start();
        }
​
    }
​
    static class ThreadDemo implements Runnable {
        Integer id;
​
        public ThreadDemo(Integer id) {
            this.id = id;
        }
​
        @Override
​
      public void run() {
            try {
                TimeUnit.MILLISECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            for(int i=0;i<2;i++){
                lock.lock();
                System.out.println("获得锁的线程:"+id);
                lock.unlock();
            }
        }
    }
}
复制代码

非公平锁示例

非公平锁那就随机的获取,谁运气好,cpu时间片轮到哪个线程,哪个线程就能获取锁

   static Lock lock = new ReentrantLock(false);//参数为false,当然我们也可以不写,默认就是false
复制代码

ReentrantLock和synchronized对比

(1)synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。

(2)synchronized可重入,因为加锁和解锁自动进行,不必担心最后是否释放锁;ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。

(3)synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以相应中断。

总结

ReentrantLock是一种可重入的,可实现公平性的互斥锁,它的设计基于AQS框架,可重入和公平性的实现逻辑都不难理解,每重入一次,state就加1,当然在释放的时候,也得一层一层释放。至于公平性,在尝试获取锁的时候多了一个判断:是否有比自己申请早的线程在同步队列中等待,若有,去等待;若没有,才允许去抢占。

Guess you like

Origin juejin.im/post/7032930760034091021