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 的关键。

相关推荐
深蓝AI1 小时前
Python 3.13 的 Queue.shutdown:异步消费者终于能正常收工了
后端
武子康2 小时前
MultiNet6 空闲崩溃:`EXCVADDR=0x8` 后又出现 `CORRUPT HEAP`
人工智能·后端·agent
武子康3 小时前
MultiNet7 每轮都 clean,ESP32-P4 内存为什么还在掉?
人工智能·后端·agent
超级架构师3 小时前
PRAXO-CORE 2.5.0:用 conformance 和显式边界构建 Go Agent 框架
开发语言·人工智能·后端·golang·ai编程·智能体框架·praxo-core
陈随易4 小时前
AI 运维服务器,安全又可靠的方法
前端·后端·程序员
IT_陈寒5 小时前
JavaScript的this坑人实录,这次我真的记下来了
前端·人工智能·后端
starzy19906 小时前
Scala类和对象:从构造器到样例类的完整指南
开发语言·后端·scala
梦影_6 小时前
MySQL进阶教程(五)—— SQL调优(下)
android·大数据·数据库·后端·sql·mysql·database
考虑考虑6 小时前
mariadb数据库
数据库·后端·mariadb
明月_清风6 小时前
用自然语言操控真机:Google Artemis 移动端 AI Agent 上手与实践
人工智能·后端