前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ReentrantLock 用法详解

ReentrantLock 用法详解

作者头像
用户3147702
发布2022-06-27 12:44:23
6670
发布2022-06-27 12:44:23
举报
文章被收录于专栏:小脑斧科技博客

1. 概述

此前的文章中我们介绍了 synchronized 锁的使用及实现原理: synchronized 的使用及实现原理 文中,我们看到,jdk1.6 对 synchronized 锁进行了一系列的优化,使得我们再也不用为 synchronized 锁的性能担忧,在此之前,synchronized 锁因为其性能问题是很少被使用的,那时,最常用的锁结构就是今天我们要介绍的 ReentrantLock 锁。 虽然时至今日,优化后的 synchronized 锁的性能已经与 ReentrantLock 接近,但 ReentrantLock 仍然具备着 synchronized 所不具备的很多优势: 1. 吞吐量更高、执行效率更高 2. 支持公平锁、非公平锁两种模式 3. 更加灵活精准的等待与唤醒 4. 可中断锁、轮询锁 5. 可伸缩性强 6. 支持条件变量 因此,在高度竞争的并发环境下,以及较为复杂的使用场景中,ReentrantLock 都是 synchronized 的有力替代品。

本文,我们就来介绍一下 ReentrantLock 的用法,下一篇文章中,我们详细的剖开源码解析 ReentrantLock 的实现原理。

2. ReentrantLock 的基本使用 — 加锁和解锁

ReentrantLock 类提供了最基本的加锁和解锁方法:

代码语言:javascript
复制
public void lock();
public void unlock();

我们通过最基本的加锁方法实现上一篇日志中提到的自增方法锁。

代码语言:javascript
复制
class Counter {
    private static int counter = 0;
    private static ReentrantLock lock = new ReentrantLock();

    public static int getCounter() {
        return counter;
    }

    public static void increase() {
        try {
            lock.lock();
            counter++;
        } finally {
            lock.unlock();
        }
    }

    private Counter() {};
}

这个方法保证了线程安全,他和 synchronized 关键字实现了相同的效果:

代码语言:javascript
复制
class Counter {
    private static int counter = 0;

    public static int getCounter() {
        return counter;
    }

    public synchronized static void increase() {
        counter++;
    }

    private Counter() {};
}

显然,synchronized 关键字的实现更为简洁和清晰,同时,如果 ReentrantLock 忘记调用 unlock 方法将会造成死锁,这是必须要注意的一点。 因此,如果仅仅是想要进行上面代码中这样的加锁和解锁,synchronized 还是最好的选择。

3. 公平模式与非公平模式

使用 synchronized 锁是不保证等待的线程获取到锁的顺序的,这就是非公平锁,除了默认的非公平锁构造方法外,ReentrantLock 还提供了一个带有 boolean 参数的构造方法:

代码语言:javascript
复制
public ReentrantLock(boolean fair);

如果传入参数为 true,则会创建公平锁,所谓的公平锁,就是保证了先进入等待的线程一定先获取到锁。

可以通过 isFair 方法查询 ReentrantLock 对象是否是公平锁:

代码语言:javascript
复制
public final boolean isFair();

4. 非阻塞式锁、时间限制锁与可中断锁

ReentrantLock 提供了 tryLock 方法与 lockInterruptibly 方法用来实现非阻塞式锁、时间限制锁与可中断锁。

代码语言:javascript
复制
public boolean tryLock()    // 尝试获取锁,立即返回获取结果
public boolean tryLock(long timeout, TimeUnit unit)    // 尝试获取锁,最多等待 timeout 时长
public void lockInterruptibly()    // 可中断锁,调用线程 interrupt 方法,则锁方法抛出 InterruptedException

以上三种锁方式,synchronized 都是无法实现的,正如我们上一篇日志中所提到,interrupt 方法是不会中止正在等待获取 synchronized 锁的线程的。

5. Condition 与线程等待

Object 类提供了只能在 synchronized 代码块中使用的 wait、notify、notifyAll,ReentrantLock 也拥有类似但更为强大的等待和唤醒机制,这就是通过 Condition 对象唤醒的。

5.1. Condition

通过 newCondition 方法,可以创建出 Condition 对象。

代码语言:javascript
复制
public Condition newCondition();

Condition 接口提供了如下的方法:

代码语言:javascript
复制
void await();                                // 可被中断的等待
boolean await(long time, TimeUnit unit);    // 最多等待 time 时长的可中断等待
long awaitNanos(long nanosTimeout);            // 最多等待 nanosTimeout 毫秒的可中断等待
boolean awaitUntil(Date deadline);            // 等待直到指定时间的可中断等待
void awaitUninterruptibly();                // 不可中断的等待
void signal();                                // 唤醒一个线程
void signalAll();                            // 唤醒所有等待中的线程

上面的五个等待方法中,除了 awaitUninterruptibly 方法,其他四个都可以被 interrupt 方法中断,而 signal 和 signalAll 方法可以中断上述所有等待方法。 但是,signal 和 signalAll 方法只能唤醒通过当前 Condition 对象调用过等待方法的线程。 基于上述特性,我们可以精准的控制让某个指定的线程被唤醒,而 Object 的 notify、notifyAll 方法的唤醒则是随机的,同一个 ReentrantLock 每次调用 newCondition 方法都将获得不同的 Condition 对象。

6. 强大而丰富的查询接口

除了上述强大的加锁与等待、唤醒接口外,ReentrantLock 还提供了丰富而强大的查询接口,让你了解到锁相关的各种情况:

代码语言:javascript
复制
int getHoldCount();        // 获取当前线程持有该锁的次数
boolean isHeldByCurrentThread();    // 判断当前线程是否持有该锁
boolean isLocked();        // 获取锁状态是否为加锁状态
boolean isFair();        // 当前锁是否是公平锁
Thread getOwner();        // 获取持有锁的线程
boolean hasQueuedThreads();            // 判断当前锁是否有线程在等待
boolean hasQueuedThread(Thread thread);    // 判断指定线程是否在等待该锁
int getQueueLength();    // 获取正在等待该锁的线程数量
boolean hasWaiters(Condition condition);    // 判断是否有线程等待在该 Condition 对象上
int getWaitQueueLength(Condition condition);    // 获取等待在该 Condition 对象的线程数
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-08-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小脑斧科技博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 概述
  • 2. ReentrantLock 的基本使用 — 加锁和解锁
  • 3. 公平模式与非公平模式
  • 4. 非阻塞式锁、时间限制锁与可中断锁
  • 5. Condition 与线程等待
    • 5.1. Condition
    • 6. 强大而丰富的查询接口
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档