ReentrantLock、ReentrantReadWriteLock、StampedLock讲解

简介: ReentrantLock、ReentrantReadWriteLock、StampedLock讲解

1. 概述

多线程编程中,锁是必不可少的,因为许多并发问题都可以通过加锁来解决,例如线程安全的单例实现、线程安全的数据结构实现等等。Java提供了许多类型的锁,本文就来介绍其中三种常见的锁:ReentrantLock、ReentrantReadWriteLock、StampedLock。

2. ReentrantLock

2.1 基本概念

ReentrantLock(重入锁)是Java中的一个独占锁,也是一种可重入锁。独占锁是指同一时刻只能有一个线程获得锁,其他线程必须等待;可重入锁是指线程可多次获取同一把锁,不会自己阻塞自己。

2.2 使用方法

使用ReentrantLock的基本方法如下:

ReentrantLock lock = new ReentrantLock(); // 创建锁对象
lock.lock(); // 获取锁
try {
    // 执行需要加锁的代码
} finally {
    lock.unlock(); // 释放锁
}

在上面的代码中,首先创建一个ReentrantLock对象,然后在需要加锁的代码执行前调用lock()方法获取锁,在需要释放锁的地方使用unlock()方法释放锁。

需要注意的是,在使用ReentrantLock时,要保证锁的获取和释放要在try…finally块中进行。因为在试图获取锁的过程中,如果线程被中断(interrupt),那么当前线程也需要释放锁资源。

2.3 特性

ReentrantLock有一些特性:

  • 重入性:同一个线程可以反复获取同一把锁,不会造成死锁。
  • 公平锁和非公平锁:ReentrantLock提供了两种获取锁的方式:公平锁和非公平锁。公平锁是指等待时间最长的线程优先获取锁,而非公平锁是指线程直接尝试获取锁,如果失败了才会进入等待队列。默认情况下,ReentrantLock是非公平锁。
  • 可中断:ReentrantLock提供了可中断的获取锁的方式,即在等待锁的过程中,如果线程被中断,则会抛出InterruptedException异常。在使用可中断获取锁的方式时,需要捕获InterruptedException异常。
  • 条件变量:ReentrantLock中可以使用Condition对象来实现线程间的通信与同步。Condition对象和锁对象是绑定在一起的,一个锁对象可以创建多个Condition对象,用于不同的等待队列。常见的方法有await()、signal()和signalAll()。

2.4 总结

ReentrantLock是一种可重入锁,提供了公平锁和非公平锁、可中断获取锁和条件变量等特性,使用起来比较灵活,但也比较复杂,需要手动控制加锁和释放锁的过程。

3. ReentrantReadWriteLock

3.1 基本概念

ReentrantReadWriteLock(可重入读写锁)是Java中另一种常用的锁,也是一种可重入锁。与ReentrantLock不同的是,ReentrantReadWriteLock既可以支持独占锁,也可以支持共享锁。共享锁是指同一时刻可以有多个线程读取共享资源,但只能有一个线程写入共享资源;独占锁是指同一时刻只能有一个线程获得锁,其他线程必须等待。因此,ReentrantReadWriteLock适用于读多写少的场景,可以提高并发读操作的效率。

3.2 使用方法

使用ReentrantReadWriteLock的基本方法如下:

ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); // 创建锁对象
lock.readLock().lock(); // 获取读锁
try {
    // 执行需要读取共享资源的代码
} finally {
    lock.readLock().unlock(); // 释放读锁
}

在上面的代码中,首先创建一个ReentrantReadWriteLock对象,然后在需要读取共享资源的代码执行前调用readLock().lock()方法获取读锁,在需要释放锁的地方使用readLock().unlock()方法释放读锁。

如果需要写入共享资源,则需要获取写锁,相应地,释放锁时需要调用writeLock().unlock()方法。

需要注意的是,在使用ReentrantReadWriteLock时,要保证读锁和写锁的获取和释放要在try…finally块中进行。

3.3 特性

ReentrantReadWriteLock有一些特性:

  • 重入性:同一个线程可以反复获取同一把锁,不会造成死锁。
  • 公平锁和非公平锁:ReentrantReadWriteLock提供了公平锁和非公平锁,与ReentrantLock类似。默认情况下,ReentrantReadWriteLock是非公平锁。
  • 支持读写分离:ReentrantReadWriteLock支持读写分离,提高并发读的效率,并且不会阻塞读和读之间的操作。
  • 降低锁的粒度:ReentrantReadWriteLock可以将锁的粒度降低,提高并发度。
  • 可重入:ReentrantReadWriteLock是可重入的。

3.4 总结

ReentrantReadWriteLock是一种可重入读写锁,适用于读多写少的场景,提供了公平锁和非公平锁、支持读写分离、降低锁的粒度等特性。使用起来比ReentrantLock稍微复杂一些,但也比较灵活。

4. StampedLock

4.1 基本概念

StampedLock(标记锁)是Java 8中新增的锁机制。它是一种乐观锁,允许多个线程在没有互相干扰的情况下访问共享资源。相比于ReentrantLock和ReentrantReadWriteLock,StampedLock更适用于读多写少、并发度高的场景,也可以用于提高读操作的性能。

4.2 使用方法

StampedLock的基本使用方法如下:

StampedLock lock = new StampedLock(); // 创建锁对象
long stamp = lock.tryOptimisticRead(); // 尝试获取乐观读锁
// 执行读操作
if (lock.validate(stamp)) {
    // 检查是否可用
    // 执行读操作
} else {
    // 尝试获取悲观读锁
    stamp = lock.readLock(); // 获取悲观读锁
    try {
        // 执行读操作
    } finally {
        lock.unlockRead(stamp); // 释放悲观读锁
    }
}

在上面的代码中,首先创建一个StampedLock对象,然后使用tryOptimisticRead()方法尝试获取乐观读锁。如果获取成功,则可以执行读操作;如果获取失败,则需要使用读锁(悲观锁)来获取资源。在获取锁后,执行完读操作后需要释放锁。

StampedLock还提供了其他类型的锁,如悲观读锁、写锁等。使用方法和ReentrantReadWriteLock类似。


相关文章
|
SQL 存储 运维
Flyway基本介绍及基本使用
使用5W1H方式介绍一下在Java项目开发中使用Flyway来管理数据库版本。。
10572 0
Flyway基本介绍及基本使用
|
缓存 监控 安全
Spring AOP 详细深入讲解+代码示例
Spring AOP(Aspect-Oriented Programming)是Spring框架提供的一种面向切面编程的技术。它通过将横切关注点(例如日志记录、事务管理、安全性检查等)从主业务逻辑代码中分离出来,以模块化的方式实现对这些关注点的管理和重用。 在Spring AOP中,切面(Aspect)是一个模块化的关注点,它可以跨越多个对象,例如日志记录、事务管理等。切面通过定义切点(Pointcut)和增强(Advice)来介入目标对象的方法执行过程。 切点是一个表达式,用于匹配目标对象的一组方法,在这些方法执行时切面会被触发。增强则定义了切面在目标对象方法执行前、执行后或抛出异常时所
17564 4
|
人工智能 IDE 程序员
GitHub Copilot 免费了!程序员们的福音来了!
《GitHub Copilot 免费了!程序员们的福音来了!》 近日,GitHub 宣布其 AI 编程助手 GitHub Copilot 现在可以免费使用。曾经每月需支付 10 美元订阅费的 Copilot,现在向所有人开放免费版本,这对个人开发者、初学者和小型团队来说是个大好消息。免费版支持 GPT 和 Claude 模型,并提供每月 2000 次代码补全和 50 条聊天消息等核心功能。用户只需注册或登录 GitHub 账户,在 VS Code 中安装扩展并激活免费版即可使用。此外,Visual Studio Code 也完全免费,进一步降低了开发门槛。 除了
12634 7
GitHub Copilot 免费了!程序员们的福音来了!
|
测试技术 Linux 应用服务中间件
Linux测试工具httpd-tools
Linux测试工具httpd-tools
737 0
|
消息中间件 NoSQL Kafka
订单超时取消的11种方式(非常详细清楚)
订单超时取消的11种方式(非常详细清楚)
8622 5
订单超时取消的11种方式(非常详细清楚)
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
2256 1
|
消息中间件 存储 Java
吃透 RocketMQ 消息中间件,看这篇就够了!
本文详细介绍 RocketMQ 的五大要点、核心特性及应用场景,涵盖高并发业务场景下的消息中间件关键知识点。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
吃透 RocketMQ 消息中间件,看这篇就够了!
|
消息中间件 JSON Java
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
Spring Boot、Spring Cloud与Spring Cloud Alibaba版本对应关系
32102 0