ReentrantLock的使用和原理详解

多线程系列(九) -ReentrantLock常用方法详解 在上一篇文章中,我们介绍了ReentrantLock类的一些基本用法,今天我们重点来介绍一下ReentrantLock其它的常用方法,以便对ReentrantLock类的使用有更深入的理解。 阅读详情


一、ReentrantLock 小例子

import java.util.concurrent.locks.ReentrantLock;
public class ReentrantLockTest extends Thread {
    public static ReentrantLock lock = new ReentrantLock();
    public static int i = 0;

    public ReentrantLockTest(String name) {
        super.setName(name);
    }

    @Override
    public void run() {
        for (int j = 0; j < 10000000; j++) {
            lock.lock();
            try {
                System.out.println(this.getName() + " " + i);
                i++;
            } finally {
                lock.unlock();
            }
        }
    }

    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        ReentrantLockTest test1 = new ReentrantLockTest("thread1");
        ReentrantLockTest test2 = new ReentrantLockTest("thread2");

        test1.start();
        test2.start();
        test1.join();
        test2.join();
        System.out.println(i);
    }
}

最后的结果是 20000000;如果去掉锁,那么输出结果是一个小于20000000的不确定的数


二、ReentrantLock的优点

  • java中已经有了内置锁:synchronized,synchronized的特点是使用简单,一切交给JVM去处理,不需要显示释放
  • 从用法上可以看出,与synchronized相比, ReentrantLock就稍微复杂一点。因为必须在finally中进行解锁操作,如果不在 finally解锁,有可能代码出现异常锁没被释放,

那么为什么要引入ReentrantLock呢?

  • 在jdk1.5里面,ReentrantLock的性能是明显优于synchronized的,但是在jdk1.6里面,synchronized做了优化,他们之间的性能差别已经不明显了。

  • ReentrantLock并不是一种替代内置加锁的方法,而是作为一种可选择的高级功能。

  • 相比于synchronized,ReentrantLock在功能上更加丰富,它具有可重入、可中断、可限时、公平锁等特点。

1.可重入(其实synchronized 也是可重入的)

  • 避免堵塞:lock1.lock()获取lock1对象的锁,while1中的lock1.lock()也是尝试获取lock1对象的锁,但是lock1对象的锁已经在上面被获取了,所以这个程序会一直阻塞在这里,但是有了可重入锁,这里不再需要获取这个锁了,直接往下运行。

  • 提高效率:拿一把锁,只要没有unlock释放,可以重复使用,不需要一直获取同一把锁

lock1.lock();
while(...){
    //上面已拿到锁,这里可以重复使用
    lock1.lock();
    //lock2还要重新获取锁
    lock2.lock();
}

由于ReentrantLock是重入锁,所以可以反复得到相同的一把锁,它有一个与锁相关的获取计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1,然后锁需要被释放两次才能获得真正释放(重入锁)。

lock的底层是用CAS实现的,并且expect是0,update是1,当期望值是0相等的时候,把它替换成1,这样相当于拿到了锁,但是当真实值不等于期望值,就说明这个锁已经被别的线程拿了,需要等待释放。只有一个人能够将状态成功的更新为1,更新之后,和期望值不相等,其余线程都无法更新。

2.可中断

与synchronized不同的是,ReentrantLock对中断是有响应的.synchronized一旦尝试获取锁就会一直等待直到获取到锁。

构造一个死锁的例子,然后用中断来处理死锁

代码如下:

package concurrency.in.practice;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.util.concurrent.locks.ReentrantLock;

public class LockInterrupt extends Thread {

    public static ReentrantLock lock1 = new ReentrantLock();
    public static ReentrantLock lock2 = new ReentrantLock();

    int lock;

    public LockInterrupt(int lock, String name) {

        super(name);
        this.lock = lock;
    }

    @Override
    public void run() {
        try {
            if (lock == 1) {
                lock1.lockInterruptibly();
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    // TODO: handle exception
                }
                lock2.lockInterruptibly();
            } else {
                lock2.lockInterruptibly();
                try {
                    Thread.sleep(500);
                } catch (Exception e) {
                    // TODO: handle exception
                }
                lock1.lockInterruptibly();
            }
        } catch (Exception e) {
            // TODO: handle exception
        } finally {
            if (lock1.isHeldByCurrentThread()) {
                lock1.unlock();
            }
            if (lock2.isHeldByCurrentThread()) {
                lock2.unlock();
            }
            System.out.println(Thread.currentThread().getId() + ":线程退出");
        }
    }

    public static void main(String[] args) throws InterruptedException {
        LockInterrupt t1 = new LockInterrupt(1, "LockInterrupt1");
        LockInterrupt t2 = new LockInterrupt(2, "LockInterrupt2");
        t1.start();
        t2.start();
        Thread.sleep(1000);

        //DeadlockChecker.check();
    }

    static class DeadlockChecker {

        private final static ThreadMXBean mbean = ManagementFactory
            .getThreadMXBean();

        public static void check() {

            Thread tt = new Thread(() -> {
                {
                    // TODO Auto-generated method stub
                    while (true) {
                        long[] deadlockedThreadIds = mbean.findDeadlockedThreads();
                        if (deadlockedThreadIds != null) {
                            ThreadInfo[] threadInfos = mbean.getThreadInfo(deadlockedThreadIds);
                            for (Thread t : Thread.getAllStackTraces().keySet()) {
                                for (int i = 0; i < threadInfos.length; i++) {
                                    if (t.getId() == threadInfos[i].getThreadId()) {
                                        System.out.println(t.getName());
                                        t.interrupt();
                                    }
                                }
                            }
                        }
                        try {
                            Thread.sleep(5000);
                        } catch (Exception e) {
                            // TODO: handle exception
                        }
                    }

                }
            });
            tt.setDaemon(true);
            tt.start();
        }

    }

}

执行后,出现了死锁,可通过中断来停止线程

3.可限时

  • 超时不能获得锁,就返回false,不会永久等待构成死锁
  • 使用lock.tryLock(long timeout, TimeUnit unit)来实现可限时锁,参数为时间和单位。

例子:

package concurrency.in.practice;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

public class TryLockTest extends Thread {

    public static ReentrantLock lock = new ReentrantLock();

    public TryLockTest(String name){
        super(name);
    }

    @Override
    public void run() {
        try {
            if (lock.tryLock(5, TimeUnit.SECONDS)) {
                Thread.sleep(6000);
            } else {
                System.out.println(this.getName() + " get lock failed");
            }
        } catch (Exception e) {
        } finally {
            if (lock.isHeldByCurrentThread()) {
                System.out.println("lock.isHeldByCurrentThread: " + this.getName());
                lock.unlock();
            }
        }
    }

    public static void main(String[] args) {
        TryLockTest t1 = new TryLockTest("TryLockTest1");
        TryLockTest t2 = new TryLockTest("TryLockTest2");

        t1.start();
        t2.start();
    }

}

两个线程来争夺一把锁,获得锁的线程sleep6秒,每个线程都只尝试5秒去获得锁。
所以必定有一个线程无法获得锁。无法获得后就直接退出了。

3.公平锁

  • 一般意义上的锁是不公平的,不一定先来的线程能先得到锁,后来的线程就后得到锁。不公平的锁可能会产生饥饿现象。
  • 公平锁的意思就是,这个锁能保证线程是先来的先得到锁。虽然公平锁不会产生饥饿现象,但是公平锁的性能会比非公平锁差很多。
  • 默认是非公平锁,可修改参数new ReentrantLock(true)实现公平锁

使用方法:

public ReentrantLock(boolean fair) 
public static ReentrantLock fairLock = new ReentrantLock(true);

多线程系列(八) -ReentrantLock基本用法介绍 在之前的线程系列文章中,我们介绍到了使用synchronized关键字可以实现线程同步安全的效果,以及采用wait()、notify()和notifyAll()方法,可以实现多个线程之间的通信协调,基本可以满足并发编程的需求。 阅读详情

相关推荐

Java并发之ReentrantLock原理详解

一、ReentrantLock是什么?    ReentrantLock是Lock接口的默认实现,是一种独占锁。相对synchronized而言,ReentrantLock提供了更多的操作方式以及更细粒度的加锁方式。    主要特性:    (1)可重入。ReentrantLock是可重入锁,因为它会记录之前获得锁线程对象,保存在exclusiveOwenerThread变量中,当一个线程要获取锁...

LiQiyao的博客 1846

ReentrantLock介绍及使用(超详细)

1. Reentrantlock介绍及使用 2. 公平锁和非公平锁 3. Reentrantlock的使用案例 4. Reentrantlock使用时注意事项

Mr.绵羊的知识星球 2万+

ReentrantLock中tryLock()和lock()⽅法的区别

tryLock()表示尝试加锁,可能加到,也可能加不到,该⽅法不会阻塞线程,如果加到锁则返回true,没有加到则返回false。lock()表示阻塞加锁,线程会阻塞直到加到锁,⽅法也没有返回值。必须确保锁被获取的场景(如数据库事务、支付扣减)。的语义,但更灵活(可中断、可设置公平性)。:减少线程阻塞时间(如缓存更新、心跳检测)。:非关键任务、死锁预防(如分布式锁)。:如果锁被占用,可以立即回退或重试。如果锁被其他线程持有,当前线程会。:锁被占用时立即返回或超时放弃。:如果锁可用,则获取锁并返回。

完全体 1411

ReentrantLock的基本使用&常用方法

下面是创建一个锁然后获取再释放的一个过程,可以看到需要调用unlock()方法释放锁,为了防止程序发生异常导致不能释放锁造成程序的死锁,一般要把释放锁的代码写在finally块中,确保锁的释放。

m0_63463465的博客 7272

ReentrantLock原理详解

ReentrantLock是可重入的独占锁,同时只能有一个线程可以获取该锁,其他获取该锁的线程会被阻塞而被放入该锁的AQS阻塞队列里面。AbstractQueuedSynchronizer简称AQSAQS是一个用于构建锁和同步容器的框架。事实上concurrent包内许多类都是基于AQS构建,例如ReentrantLock,Semaphore,CountDownLatch,ReentrantReadWriteLock,FutureTask等。AQS解决了在实现同步容器时设计的大量细节问题。

流楚丶格念的博客 1720

扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)

扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码) 文章目录扩展卡尔曼滤波(EKF)理论讲解与实例(matlab、python和C++代码)理论讲解KF和EKF模型对比雅可比矩阵计算计算实例应用实例线性模型CV模型:CA模型非线性模型CTRV模型:CTRV实例(python)small demo抛物线demo飞机高度demoC++实例参考文献 我们上篇提到的卡尔曼滤波是用于线性系统,预测(运动)模型和观测模型是在假设高斯和线性情况下进行的。简单的卡尔曼滤波必须应用在符合高斯分布

O_MMMM_O的博客 10万+

【Java核心能力】上万字 ReentrantLock 原理全面详解!

本来写这篇文章是因为自己对 ReentrantLock 的了解一直都比较表面,原理了解的还不是那么的清楚,并且对 AQS 也都是一知半解,但是在面试中这些都是比较常问的内容,如果原理了解比较清楚的话,对面试会有很大的帮助,因此自己在这里也总结了一份,本来以为很快就写完了,没想到竟然写了两天,文字的话就有 6000 +,ReentrantLock 中大部分的内容也都说到了,并且配有许多图片,如果感觉内容太多的话,可以对 ReentrantLock 中加锁以及解锁内容重点阅读,希望对你有所帮助!

qq_45260619的博客 2079

解析vCard 3.0:提取电子名片中的姓名

N:LastName;FirstName;;;END:VCARD和END:VCARD标记数据块的开始和结束。N字段存储结构化姓名(分号分隔)。FN字段为直接可读的显示名称。其他字段如TELEMAIL等保存联系信息。

qq_45797625的博客 2778

详解AQS以及ReentrantLock原理

本文将针对AQS原理进行讲解,通过自定义一个不可重入锁的例子以及队ReentrantLock源码的剖析加深对AQS的理解

weixin_53216033的博客 1170

CATIA P3 V5-6R2023在Windows 11 23H2上的稳定安装与系统级配置指南

CATIA是高端制造业核心的三维参数化设计平台,其运行依赖严格的系统底层支撑。理解CATIA的BRep几何内核原理与Windows子系统(如WSL、Hyper-V)的协同机制,是保障建模稳定性与计算精度的技术前提。CATIA Run-Time Library和OpenGL硬件加速能力共同决定了曲面重建、螺纹建模等关键操作的可靠性;而.NET Framework 3.5、VC++ 2022运行库及显卡Studio驱动的精准匹配,则构成工业软件在Win11环境落地的工程基础。本文聚焦于航空、轨交、能源等领域高频

weixin_30983353的博客 631

从硬件到软件:TSMaster报文过滤全链路配置指南(含同星设备适配)

本文详细介绍了TSMaster平台下CAN/LIN/FlexRay总线的报文过滤全链路配置指南,特别针对同星TC1016等硬件的兼容性进行实战演示。从硬件层预过滤到软件层可编程过滤,提供五维过滤体系构建方法,帮助工程师提升车载诊断与总线分析效率。重点解析混合总线过滤策略优化及诊断场景下的特殊过滤方案。

tensorflowjs6的博客 401

详解ReentrantLock之Condition原理

Condition Jdk中独占锁的实现除了使用关键字synchronized外,还可以使用ReentrantLock。虽然在性能上ReentrantLock和synchr...

Daniel的博客 1万+

混合整数规划(MIP)在资源优化中的实战应用

本文深入探讨了混合整数规划(MIP)在资源优化中的实战应用,从菜市场采购到工厂调度,再到物流配送和钢铁厂切割问题。通过分支定界法和割平面法等技术,MIP能够有效解决包含整数和连续变量的复杂优化问题,提升企业运营效率。文章还介绍了现代求解器的优化策略和实际项目中的避坑指南,帮助读者更好地应用MIP技术。

weixin_30500105的博客 91

简单实现ReentrantLock,详解ReentrantLock底层原理

AbstractQueuedSynchronizer类不止服务于ReentrantLock类,因此该类里面有很多跟ReentrantLock不想关的代码存在,本文将提取ReentrantLock类和AbstractQueuedSynchronizer类的核心代码进行解释说明。本文末尾将附带经过我提取的手写的ReentrantLock代码,代码上附有我对该锁的理解的注解。的核心就是类,要了解就要先了解一、AbstractQueuedSynchronizer类。

duan614的博客 1897

Benchmark系列——UnixBench测试项深度解析与性能优化指南

本文深度解析UnixBench基准测试套件的各项测试原理,包括Dhrystone、Whetstone、系统调用、进程管理、IPC及文件I/O等核心测试项。通过详细的测试项分析,指导用户解读测试报告,并提供针对性的内核参数调整、编译优化及系统配置实战指南,帮助用户精准定位并优化系统性能瓶颈。

weixin_29230901的博客 275

2025最新OSM中国矢量数据保姆级下载指南(附百度网盘链接)

本文提供2025年OSM中国矢量数据的保姆级下载与使用指南。详细介绍了通过Geofabrik镜像站、QGIS插件及第三方平台获取数据的多种途径,重点解析了Shapefile格式数据的结构、WGS84坐标系特性,并指导进行格式转换与基础GIS应用,帮助用户高效合规地获取并利用这份开放地理数据资源。

weixin_29228781的博客 874

【第五篇】ReentrantLock原理详解【重点】

1.1 概述 ReentrantLock是Java中的最常见的锁,本文主要讲解ReentrantLock的实现原理。   ReentrantLock主要利用CAS+AQS队列来实现,它是一种独占锁、可重入锁,它支持公平锁和非公平锁模式。 1.2 ReentrantLock原理 探究ReentrantLock原理之前我们先来看一个ReentrantLock的使用示例 private Lock lock = new ReentrantLock(); public void test(){ l

ᶻᶻᶻ 枕星河的博客 2951

从CAD到Web:高效转换STEP/IGES模型为GLB格式的实践指南

本文详细介绍了如何将工业设计中的STEP/IGES模型高效转换为Web友好的GLB格式。通过PythonOCC和gltf-pipeline等工具链,实现从CAD到Web的无缝转换,大幅提升模型加载速度和展示效果。文章包含实战案例、优化技巧和常见问题解决方案,帮助开发者快速掌握3D模型转换技术。

weixin_29072299的博客 507

ReentrantLock原理与使用详解

实现。相比。

zhiyuanIT的专栏 1082

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

从ReentrantLock详解AQS原理源码解析

// java.util.concurrent.locks.AbstractQueuedSynchronizer#addWaiter // 在队列尾部创建一个结点,值为当前线程和传入的模式 private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure //

NeverTh 324

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

ReentrantLock实现原理详解

ReentrantLock是Java并发包中用于实现可重入锁的类,基于AQS(AbstractQueuedSynchronizer,抽象队列同步器)实现,支持公平锁和非公平锁。

Bbb36921的博客 640

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

ReentrantLock原理源码详解

I)、AQS介绍 要理解ReentrantLock,首先必须要理清楚AQS以及AQS是什么,有哪些重要属性,以及整个ReentrantLock的继承关系结构是什么样的。这部分对于第一次接触AQS来说却是有点绕。 1、什么是AQS 个人简单理解AQS,AQS(AbstractQueuedSynchronize)按照他的字面意思: 1、Abstract抽象的,说明该类是一个抽象类,具体一些如何控制同步策略需要子类去实现。 2、Queued队列,说明该同步器需要用一个队列来存放竞争锁失败的线程,以便于锁被释放

wenpan的博客 541

详解synchronized 和ReentrantLock两种锁实现原理

概述 Java 中的并发锁大致分为隐式锁和显式锁两种。隐式锁就是我们最常使用的 synchronized 关键字,显式锁主要包含两个接口:Lock 和 ReadWriteLock,主要实现类分别为ReentrantLock 和 ReentrantReadWriteLock,这两个类都是基于AQS(AbstractQueuedSynchronizer) 实现的。还有的地方将CAS也称为一种锁,...

ly199108171231的博客 4502

并发编程 — ReentrantLock 原理详解

一、概述 ReentrantLock 是JDK1.5 引入的J.U.C包中的一个比较重要的可重入的、互斥的并且支持公平和非公平的锁,其实现了 Lock接口,其内部是通过 AQS + CAS 原理实现的。其具备 synchronized 关键字加锁的所有功能,并且还具备一些 synchronized 锁不具备的功能,比如:尝试拿锁,支持中断、支持超时等待等。 二、什么是可重入锁 可重入锁,顾明思议,就是支持重进入的锁,它表示该锁能够支持同一个线程对资源的重复加锁。通俗来讲就是 如果线程 A 已经获取的锁

small_love的专栏 622
上一篇: 属性动画的使用和原理解析
下一篇: synchronized锁原理详解
浮空over
博客等级 码龄7年 6粉丝 33原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值