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

相关推荐
源代码•宸10 分钟前
大厂技术岗面试之谈薪资
经验分享·后端·面试·职场和发展·golang·大厂·职级水平的薪资
晚霞的不甘1 小时前
CANN 编译器深度解析:UB、L1 与 Global Memory 的协同调度机制
java·后端·spring·架构·音视频
喵叔哟1 小时前
06-ASPNETCore-WebAPI开发
服务器·后端·c#
Charlie_lll2 小时前
力扣解题-移动零
后端·算法·leetcode
打工的小王2 小时前
Spring Boot(三)Spring Boot整合SpringMVC
java·spring boot·后端
80530单词突击赢4 小时前
JavaWeb进阶:SpringBoot核心与Bean管理
java·spring boot·后端
爬山算法4 小时前
Hibernate(87)如何在安全测试中使用Hibernate?
java·后端·hibernate
WeiXiao_Hyy5 小时前
成为 Top 1% 的工程师
java·开发语言·javascript·经验分享·后端
苏渡苇5 小时前
优雅应对异常,从“try-catch堆砌”到“设计驱动”
java·后端·设计模式·学习方法·责任链模式
long3165 小时前
Aho-Corasick 模式搜索算法
java·数据结构·spring boot·后端·算法·排序算法