Java ReentrantLock 核心用法

ReentrantLock 是 Java 中处理并发问题的强大工具,用于解决多线程下的竞态条件(如 count++ 操作导致的数据不一致)。本文旨在展示其最核心、最标准的用法。

1. 实战代码示例

以下代码通过对比加锁与否,直观展示 ReentrantLock 的作用。

java 复制代码
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {

    // 1. 实例化一个 ReentrantLock
    private final ReentrantLock lock = new ReentrantLock();
    private int count = 0;

    /**
     * 不使用锁的递增方法(线程不安全)
     */
    public void incrementWithoutLock() {
        count++;
    }

    /**
     * 使用 ReentrantLock 的递增方法(线程安全)
     */
    public void incrementWithLock() {
        // 2. 获取锁
        lock.lock();
        try {
            // 3. 在 try 块中执行所有共享资源操作
            count++;
        } finally {
            // 4. 在 finally 块中释放锁,确保锁一定会被释放
            lock.unlock();
        }
    }

    public int getCount() {
        return count;
    }

    public void reset() {
        count = 0;
    }

    public static void main(String[] args) throws InterruptedException {
        final int threadCount = 100;
        final int incrementsPerThread = 1000;
        final int expectedCount = threadCount * incrementsPerThread;
        ExecutorService executor = Executors.newFixedThreadPool(threadCount);
        ReentrantLockDemo demo = new ReentrantLockDemo();

        // --- 场景一:不使用锁 ---
        System.out.println("--- 场景一:不使用锁 (线程不安全) ---");
        for (int i = 0; i < threadCount; i++) {
            for (int j = 0; j < incrementsPerThread; j++) {
                executor.submit(demo::incrementWithoutLock);
            }
        }
        executor.shutdown();
        executor.awaitTermination(5, TimeUnit.SECONDS);
        System.out.println("预期结果: " + expectedCount);
        System.out.println("实际结果: " + demo.getCount());
        System.out.println("-------------------------------------\n");

        // --- 场景二:使用 ReentrantLock ---
        System.out.println("--- 场景二:使用 ReentrantLock (线程安全) ---");
        demo.reset();
        executor = Executors.newFixedThreadPool(threadCount);
        for (int i = 0; i < threadCount; i++) {
            for (int j = 0; j < incrementsPerThread; j++) {
                executor.submit(demo::incrementWithLock);
            }
        }
        executor.shutdown();
        executor.awaitTermination(5, TimeUnit.SECONDS);
        System.out.println("预期结果: " + expectedCount);
        System.out.println("实际结果: " + demo.getCount());
        System.out.println("-------------------------------------");
    }
}

2. 运行结果

markdown 复制代码
--- 场景一:不使用锁 (线程不安全) ---
预期结果: 100000
实际结果: 99654
-------------------------------------

--- 场景二:使用 ReentrantLock (线程安全) ---
预期结果: 100000
实际结果: 100000
-------------------------------------

结果清晰地表明,不使用锁导致了数据错误,而 ReentrantLock 保证了计算的正确性。

3. 核心使用范式

ReentrantLock 的使用必须遵循以下结构,以确保锁在任何情况下(包括异常)都能被释放,从而防止死锁。

java 复制代码
lock.lock(); // 1. 获取锁
try {
    // 2. 执行需要保护的代码
} finally {
    lock.unlock(); // 3. 在 finally 块中释放锁
}

结论:synchronized 的自动锁管理不同,ReentrantLock 需要开发者手动保证锁的释放。严格遵守 try-finally 范式是正确使用 ReentrantLock 的关键。

相关推荐
ping某12 分钟前
一个“日志备份”需求,为什么会牵出整个 Linux 日志系统?
后端·架构
血小溅30 分钟前
Spring AI 对 Skill/MCP 的支持全景整理
后端
晓杰'41 分钟前
从0到1实现Balatro游戏后端(8):Skip Blind与Tag奖励机制设计与实现
后端·websocket·typescript·项目实战·nestjs·状态管理·游戏服务器
叫我:松哥1 小时前
基于Flask框架的校园二手书籍交易平台,注重校园场景的特殊需求,通过学号认证保障用户真实性
后端·python·sqlite·flask·bootstrap
终将老去的穷苦程序员1 小时前
基于SpringBoot的餐饮管理系统
java·spring boot·后端
张忠琳1 小时前
【Go 1.26.4】Golang Map 深度解析
开发语言·后端·golang
一条泥憨鱼2 小时前
Java开发效率神器:Lombok从入门到精通!
java·后端·学习·开发·lombok
熠熠仔2 小时前
Spring Boot 与 MyBatis-Plus 空间几何数据集成指南
spring boot·后端·mybatis
AI 小老六2 小时前
Google AX 控制面拆解:分布式 Agent 如何把断点恢复、审计策略和执行调度收进同一条链路
人工智能·分布式·后端·ai·架构·ai编程
YHHLAI2 小时前
从零搭建一个 RESTful Todo 服务 —— Bun + TypeScript 全栈最小闭环
后端·typescript·restful