• Java并发编程之ReentrantLock重入锁原理解析


    Java并发编程之ReentrantLock重入锁原理解析

    在多线程编程中,同步是一种重要的技术,用于控制对共享资源的并发访问。ReentrantLock是Java并发编程库中的一个重要工具,用于实现互斥访问共享资源的目的。ReentrantLock可以理解为一个可重入的互斥锁,它允许一个线程多次获取同一把锁,避免了在多线程环境中对共享资源的并发访问。

    一、ReentrantLock实现

    1. 基本原理

    ReentrantLock通过内部计数器来记录锁的占用情况。当一个线程尝试获取锁时,会先检查计数器,如果计数器为0,说明锁未被占用,该线程可以获取锁并执行临界区的代码。如果计数器不为0,说明锁已被其他线程占用,该线程将会被阻塞,并将自己加入到等待队列中。当锁的占用者释放锁时,会检查等待队列,唤醒一个等待的线程。

    2. 线程阻塞与唤醒机制

    当线程请求锁时,如果锁被占用,线程会进入阻塞状态并将自己加入到等待队列中。当锁的占用者释放锁时,会唤醒一个等待的线程。这个过程是通过JVM的Unsafe类来实现的,通过调用park()方法来实现线程的阻塞和唤醒。当调用park()方法时,线程会释放CPU资源并进入阻塞状态,等待其他线程调用unpark()方法来唤醒它。当调用unpark()方法时,等待队列中的线程会被唤醒并尝试获取锁。

    3. 公平锁与非公平锁

    ReentrantLock有两种类型:公平锁和非公平锁。公平锁按照线程请求锁的顺序分配锁,而非公平锁则没有这个限制。在创建ReentrantLock对象时,可以通过参数来指定是使用公平锁还是非公平锁。

    4. 锁状态的改变

    ReentrantLock的状态分为四种:公平锁和非公平锁分别有0和1个等待线程两种状态,还有锁定状态和未锁定状态。这些状态的改变需要通过lock()、unlock()、tryLock()等接口进行操作。

    二、ReentrantLock工作原理分析

    1. 锁的获取与释放

    ReentrantLock提供了两种获取锁的方式:lock()和tryLock()。lock()方法会一直阻塞直到获取到锁,而tryLock()方法则会立即返回是否获取到了锁。当一个线程释放锁时,会调用unlock()方法来释放锁,释放后的锁会被加入到等待队列中,等待其他线程来获取。

    2. 公平性策略

    ReentrantLock支持公平锁和非公平锁两种策略。公平锁按照线程请求锁的顺序分配锁,而非公平锁则没有这个限制。在实现上,公平锁会使用一个FIFO队列来保存等待的线程,而非公平锁则不会。这种策略可以有效地避免“饥饿”问题。

    3. 可重入特性

    ReentrantLock支持可重入特性,即一个线程可以多次获取同一个锁。在实现上,当一个线程再次获取已经获取的锁时,会直接返回成功状态,而不会进行阻塞。这就意味着同一个线程可以多次获得同一把锁,但每次获取都需要释放,否则会导致死锁。

    三、简单Java代码示例

    下面是一个使用ReentrantLock实现同步访问的简单示例:

    import java.util.concurrent.locks.ReentrantLock;
    
    public class ReentrantLockDemo {
        private final ReentrantLock lock = new ReentrantLock();
        private int count = 0;
    
        public void increment() {
            lock.lock();  // 获取锁
            try {
                count++;  // 修改共享资源
            } finally {
                lock.unlock();  // 释放锁
            }
        }
    
        public int getCount() {
            return count;  // 返回共享资源值
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这个示例中,我们使用ReentrantLock来保护对count变量的访问。increment()方法使用lock()和unlock()方法来确保在修改count变量的过程中不会被其他线程干扰。getCount()方法返回当前count的值,实现了读写分离。
    四、总结

    ReentrantLock是Java并发编程库中的一个重要工具,它提供了一种可重入的互斥访问共享资源的方式。通过内部计数器来实现锁的占用情况的记录,同时支持公平锁和非公平锁两种策略以及可重入特性。使用ReentrantLock可以有效地避免并发访问共享资源时的线程安全问题。

  • 相关阅读:
    浅析即时通讯开发前置 HTTP SSO 单点登陆接口的原理
    MAC版InDesign 2022 17.4(ID2022)已发布,原生支持Intel和M1/M2三系统,速度提升80%
    kube-prometheus 监控系统使用与总结
    GIS杂记(三):MaxEnt模型中的图像地理范围不匹配【全网最好的方法,没有之一】
    数据结构-快速排序-C语言实现
    C#中IsNullOrEmpty和IsNullOrWhiteSpace的使用方法有什么区别?
    【面试补漏】vue.$nextTick的原理
    丢失d3dcompiler 47.dll的修复方案,哪个更值得推荐
    华为机试 - 最少交换次数
    在express中使用session认证
  • 原文地址:https://blog.csdn.net/a1774381324/article/details/133718189