Lock的学习与使用

第三篇(2):lock的学习与使用 今天我们来学习并发包下的Lock(锁)的知识。之所以Java在有synchronized的情况下,还提供基于lock接口实现的锁。是由于lock有一些synchronized没有特性。可以再发生死锁时相应中断,释放锁。 阅读详情

       多线程是复杂的,为了使开发者写出简单、安全的并发程序,JDK提供了大量的API和框架。在上一节,大家已经认识了线程间同步的一个重要手段sychronized,现在,我们来学习一下JDK1.5新增的线程同步工具类Lock。Lock不仅具有sychronized的所有特性,在它的基础上,增加了许多其它的功能,相较于sychronized,Lock更加灵活。当然,我们不是说sychronized完全没有用了,只是Lock的功能更加强大。

       在线程同步中,sychronized关键字是一种最简单的方式,要想我们的程序实现更多更好的功能,Lock是必不可少的。写一个简单的例子,进入到Lock的世界中:

       从代码中看,大家应该发现了三处与业务逻辑不相关的代码,分别是创建lock对象、lock.lock()、lock.unlock()。这三句代码就相当于线程同步控制,也就是所谓的锁操作,其中lock.lock()是加锁,lock.unlock()是解锁。大家或许就会问了,使用Lock线程同步怎么这么麻烦呢?sychronized一个关键字就能做到自动加锁,解锁,lock还需要我们手动操作,强大在哪里呢?朋友们,别急,听我仔细分析一下。使用Lock进行锁操作,我们能够明显的看出哪里需要加锁,哪里需要解锁,一目了然,使用起来非常灵活。另外,这只是一个简单的例子,丰富多彩的情节总是在后面的。

       在上面的代码中,我们使用了try-catch方式,这在实际项目中基本上是一种固定的模式,这是为了防止业务逻辑出现异常,导致资源未释放的问题。 

       Lock锁也是重入锁,表明一个线程能够连续多次获取锁,但是,这里需要特别注意,多次获取,也就相应的需要进行同等数量释放。如果我们在代码中,多释放锁,会得到一个java.lang.IllegalMonitorStateException,相反,少释放锁,那么当前线程依然持有锁,这是很危险的。大家可以按照这两种情况分别写一段代码,看看结果如何。

锁的获取方式:

lock()、lockInterruptibly()、tryLock()或者tryLock(long timeout,TimeUnit unit)。

1.lock(),锁未被使用,直接获取,否则,永久等待。

2.lockInterruptibly(),当前线程未被中断,则获取锁定,如果已被中断则出现异常。处理死锁,很有帮助。

3.tryLock(),限时等待锁。方法中不加时间,如果线程没有获得锁,则立即返回false,否则,返回true。方法中加时间,则表示限时等待,超过时间未获得锁,则线程自动放弃。避免死锁,很有帮助。

测试lockInterruptibly()方法:

       这段代码,很明显,会发生死锁,当线程A获取锁1之后,进行睡眠,线程B获取锁2,之后两个线程互相请求对方持有的锁。

结果:

        从结果看出,两个线程都退出了。使用lockInterruptibly()请求锁,当我们使用interrupte()中断时,线程A放弃了对锁2的请求并释放锁1,然后退出,之后线程B获取到锁1,正常退出。虽然两个线程都退出了,但是真正完成工作的只有线程B。lockInterruptibly()进行锁中断,很轻易就解决了死锁。

测试tryLock()方法:

结果:

       这这里,我们使用tryLock()方式获取锁,结果输出中,两个时间是一致的,这就表明,使用tryLock()会立即去请求锁,当锁被其它线程所持有的时候,会立马返回false。tryLock(long timeout,TimeUnit unit)也是类似,相对来说,只是在获取锁加了等待时间,时间到达还未获取锁,也会立马返回false。利用tryLock()避免死锁是一种好的方式。

公平锁:

        大多数情况下,我们都是使用的非公平锁。通俗来说,锁的获取是随机的,即使线程A先线程B请求锁,线程A也不一定先获取锁,不会按照时间先后顺序,获取资源随机性可能导致饥饿现象,sychronized获取锁就是非公平的。如果我们想要获取公平锁,应该怎样实现呢?下面我们讲一下ReentrantLock的另一构造函数:

       通过源码注释,我们发现,当参数fair为true时,锁时公平的,相反,则是非公平的。公平锁可以帮助我们解决饥饿问题,但是公平锁需要维护一个有序队列,实现成本大,性能相对较低,因此,默认情况下,锁都是非公平的。当我们的业务没有特别需求的情况下,我们尽量使用非公平锁。下面展现了公平锁的特点:

      上述代码,我们使用new ReentrantLock(true)创建对象,指定锁是公平的。run()方法中,我们循环获取锁,看看输出:

      截取一部分输出,大家可以发现,每次获取锁的顺序都是一致的,不会发生一个线程连续把持锁的情况,从而保证了锁的公平性。当我们把fair改为false,输出结果:

       可以看到,一个线程会倾向于在此获取已经持有的锁,这种分配方式比较高效,但是无公平性,很容易出现饥饿现象。

其它方法:

int getHoldCount():获取当前线程持有该锁的次数,也就是调用lock()方法的次数。

int getQueueLength():获取正等待请求锁的线程个数。

boolean isFair():判断当前锁是否是公平锁。

boolean isHeldByCurrentThread():判断当前线程是否持有该锁。

boolean isLocked():获取该锁是否已经被任意线程所持有。

        这一节,我们大概了解Lock的实现类ReentrantLock的常用方法,它的逻辑控制灵活,在多线程程序中,我们完全可以使用ReentrantLock来代替sychronized。下一节我们将继续围绕ReentrantLock重入锁,学习Condition条件和Semaphore信号量。

 

Apple CarPlay Certification Guide December 2022 解析V1.0 Apple CarPlay Certification Guide December 2022更新说明 阅读详情

相关推荐

C# WinForms实战:5分钟用ScottPlot打造专业级示波器界面(附完整代码)

本文详细介绍了如何在C# WinForms应用中,利用ScottPlot.WinForms库快速构建一个专业级的软件示波器界面。通过从环境配置、静态波形绘制到动态数据实时更新的完整实战演示,帮助开发者高效实现高性能的波形显示功能,适用于工业监控、信号分析等多种场景。

weixin_29198045的博客 831

lock(true) 锁机制的使用

再一个系列同时操作多种表的话 最好是用事务, 这样不容易出错 数据库类型要是InnoDB, 加锁必须跟事务同时使用, 查询的时候都必须带锁, 比如: $user_mod->lock(true)->where('id=1')->select(); 这个地方用锁查询,如果查询这个user对象需要防止同时操作的话也要进行加锁,就是也要用lock(true)这种方式查...

adf1256的博客 901

动作识别(三)Win10复现OpenPose1.7.0+ST-GCN代码

动作识别(三)Win10复现OpenPose1.7.0+ST-GCN代码1.Win10系统配置OpenPose1.7.0的Python API 本人最近在研究基于骨架的动作识别方法,有幸看到端到端的ST-GCN算法,于是决定自己复现一下。(具体原理这里不介绍,大家自行查阅,比如Openpose是个啥?ST-GCN又是个啥?) 1.Win10系统配置OpenPose1.7.0的Python API 安装步骤: (1) ...

QIANFANGshiwo的博客 3042

Lock锁的基本使用

在jdk1.5后新增的ReentrantLock类同样可达到此效果,且在使用上比synchronized更加灵活 相关API: 使用ReentrantLock实现同步 lock()方法:上锁 unlock()方法:释放锁 使用Condition实现等待/通知 类似于 wait()和notify()及notifyAll() Lock锁底层基于AQS实现,需要自己封装实现自旋锁。 Synchronized —属于JDK 关键字 底层属于 C++虚拟机底层实现 Lock锁底层基于AQS实现-- 变为重量级 S

qq_33240556的博客 3583

【任何电机可使用的七段式s曲线-----包括matlab代码和simulink仿真】

S形加加速(T1)→>匀加速(T2)→减加速(T3)→>匀速(T4 )>加减速(T5)>匀减速(T6)-→>减减速(T7)

weixin_44312889的博客 6311

从SolidWorks到Simulink:手把手教你用URDF文件搭建六轴机械臂仿真模型(含STL文件配置避坑)

本文详细介绍了从SolidWorks到Simulink的六轴机械臂URDF仿真全流程,包括URDF文件导出、Simscape模型生成与调试、动力学参数获取与验证等关键步骤。重点解决了STL文件配置、关节接口设置等工程化难题,帮助开发者高效构建可控制的数字孪生体。通过实战案例和优化技巧,提升机械臂仿真效率与准确性。

weixin_26812607的博客 267

多线程 生产,消费 ProducerConsumerDemo

ProducerConsumerDemo.java /** * 资源类 */ class ShareData { private int number = 0; private Lock lock = new ReentrantLock(); private Condition condition = lock.newCondition(); public void increment() { lock.lock(); //加锁 //1

mhbsoft的博客 298

Windows10下MATLAB2017a安装与破解实战:手把手教你搞定双镜像加载

本文详细介绍了在Windows 10系统下安装和破解MATLAB 2017a的完整步骤,包括双镜像加载、许可证配置及常见问题解决方案。通过手把手教程,帮助用户顺利完成安装并优化性能,特别适合工程计算领域的初学者和专业人士。

weixin_29053383的博客 420

深入学习锁--Lock各种使用方法

深入学习锁--Lock各种使用方法

weixin_42672802的博客 2532

PICO4 VR开发调试神器:用Live Preview Plugin实现电脑串流,告别反复打包烧录的繁琐流程

本文详细介绍了PICO4 VR开发中如何使用Live Preview Plugin实现电脑串流,显著提升开发效率。通过实时预览和调试功能,开发者可以避免反复打包烧录的繁琐流程,特别适用于Unity环境下的VR应用开发。文章涵盖环境配置、连接设置、实时调试技巧及性能优化方案,是PICO4开发者的必备指南。

weixin_34110970的博客 419

告别Win11睡眠假死:深入解析Modern Standby S0与S3冲突及注册表修复方案

本文深入解析了Windows 11中Modern Standby(S0)与传统睡眠(S3)模式的冲突,该冲突是导致电脑睡眠后出现假死、断网等问题的根源。文章提供了通过修改注册表键值(PlatformAoAcOverride)强制启用稳定S3睡眠的终极修复方案,并附有详细诊断步骤与避坑指南,帮助用户彻底解决睡眠故障。

ol789012的博客 823

Lock关键字死锁

c#中有个关键字lock,它的作用是锁定某一代码块,让同一时间只有一个线程访问该代码块,下面就我个人而言谈谈lock关键字的原理和其中应注意的几个问题: lock的使用原型是: lock(X) {     //需要锁定的代码.... } 首先要明白为什么上面这段话能够锁定代码,其中的奥妙就是X这个对象,事实上X是任意一种引用类型,它在这儿起的作用就是任何线程执行到lock(X)时候,X需要独享才能运 行下面的代码,若假定现在有3个线程A,B,C都执行到了lock(X)而ABC因为此时都占有X,这时ABC就要

O Wen 1206

30分钟用 Restful ABAP Programming(RAP)模型开发一个支持增删改查的 Fiori 应用

2016年时,Jerry曾经写过一系列关于SAP Fiori Smart Template(现在更名为Fiori Elements了)的博客,介绍了所谓的MDD开发方法论 - Metadata Driven Development,即通过开发维护了对应annotation(注解)的CDS view,结合SAP WebIDE,能够花费最少的编程代价,就能够在短时间内获得一个支持增删改查的Fiori应......

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 5954

学习lock的使用

lock 关键字将语句块标记为临界区,方法是获取给定对象的互斥锁,执行语句,然后释放该锁。lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。看下面的代码进行说明。 private static object obj = new object() lock (obj) { //....

fhzh520的专栏 867

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

【JUC学习】——Lock和Synchronized使用及二者区别

众所周知,在JUC中常见的锁就是Lock和Synchronized了,主要是用于并发多线程的同步执行问题,用于在许多线程执行时对资源的限制​。锁通常需要硬件支持才可以有效实施。这种支持通常采用一个或多个原子指令,测试单个线程是否空闲。 Lock是显式加锁,锁释放。而synchronized是隐式锁,出了作用域自动释放,Lock只有代码块锁,synchronized有代码块锁和方法锁。使用Lock锁,JVM将花费较少的时间来调度线程,性能更好。并且具有更好的扩展性(提供更多的子类ReentrantLock()

时光、疏离了记忆づ童话的博客 710

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Java并发学习之十四——使用Lock同步代码块

本文是学习网络上的文章时的总结,感谢大家无私的分享。 Java提供另外的机制用来同步代码块。它比synchronized关键字更加强大、灵活。Lock 接口比synchronized关键字提供更多额外的功能。在使用Lock时需要注意的是要释放Lock锁。 package chapter2; import java.util.concurrent.locks.Lock; import

我的编程之路 3003

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

[Java学习笔记]并发编程——Lock的使用

Synchronized\Lock的比较 初学Java多线程编程我们发现除了关键字Synchronized以外,还有各种各样的Lock类型,那么我们就会想:既然已经有了Synchronized这个关键字帮助我们实现线程同步,管理资源的有序和谐访问,那么Lock又有什么存在的必要呢? 为此我们需要了解Synchronized的缺陷: 我们知道在Synchronized同步机制下,获取锁的线程释放锁...

DoneBug的博客 352

【学习笔记】为什么不使用lock(this)

一. 为什么要lock,lock了什么? 当我们使用线程的时候,效率最高的方式当然是异步,即各个线程同时运行,其间不相互依赖和等待。但当不同的线程都需要访问某个资源的时候,就需要同步机制了,也就是说当对同一个资源进行读写的时候,我们要使该资源在同一时刻只能被一个线程操作,以确保每个操作都是有效即时的,也即保证其操作的原子性。lock是C#中最常用的同步方式,格式为lock(objectA

778

Python学习:threading模块 lock、Rlock的使用

在使用多线程的应用下,如何保证线程安全,以及线程之间的同步,或者访问共享变量等问题是十分棘手的问题,也是使用多线程下面临的问题,如果处理不好,会带来较严重的后果,使用python多线程中提供Lock 、Rlock 、Semaphore 、Event 、Condition 用来保证线程之间的同步,后者保证访问共享变量的互斥问题。

Python热爱者的博客 1101

Java多线程学习笔记16之Lock的使用

详细代码见:github代码地址   本节内容: 1) Lock接口/ReentrantLock类/lock()/unlock()方法文档翻译     翻译中包含了此重入锁与synchronized方法及语句块之间区别及优缺点 2) 使用ReentrantLock实现同步 第四章 Lock的使用 内容: Java5中的Lock对象也能实现同步的效果,而且在使用上也更加方便。...

you are sherlocked by me! 1336

并发编程学习(9) ——Lock的初步使用以及分析

前言 在并发编程学习(8) —— 管程的文章中介绍了管程,管程中最需要解决的问题是互斥和同步,而Lock就负责解决互斥问题,Condition就负责解决同步问题。 但是,之前提到的synchronized也是一种管程的实现方式,那既然有了synchronized为什么还要再造Lock和Condition?在之前的并发编程学习(5) —— 如何解决死锁中提到过死锁这个问题,死锁的解决方法有三种: ...

weixin_38168947的博客jAbP)aWAuNkA 383

Java多线程学习笔记17之Lock的使用

详细代码见:github代码地址   本节内容: 1) Lock/ReentrantLock的newCondition()方法及Condition类/await、signal方法文档翻译 2) Condition实现等待/通知使用(错误示例及正确示例) 3) 使用多个Condition实现通知部分线程 4) 实现消费者和生产者模型(利用await()及signal()方法)   ...

you are sherlocked by me! 951

Java多线程学习(六)——Lock的使用

锁是用于通过多个线程控制对共享资源的访问的工具。通常,锁提供对共享资源的独占访问:一次只能有一个线程可以获取锁,并且对共享资源的所有访问都要求首先获取锁。 但是,一些锁可能允许并发访问共享资源,如ReadWriteLock的读写锁。Java5之后并发包中新增了Lock接口以及相关实现类来实现锁功能。 虽然synchronized方法和语句的范围机制使得使用监视器锁更容易编程,并且有助于避免涉及锁的...

xiaosen的博客 267

Java多线程学习(五)Lock锁的使用

Lock接口 1.Lock接口介绍 锁是用于通过多个线程控制对共享资源的访问的工具。通常,锁提供对共享资源的独占访问:一次只能有一个线程可以获取锁,并且对共享资源的所有访问都要求首先获取锁。 但是,一些锁可能允许并发访问共享资源,如ReadWriteLock的读写锁。 在Lock接口出现之前,Java程序是靠synchronized关键字实现锁功能的。JDK1.5之后并发包中新增了Lock接口以...

陈东东的博客 543

第41天学习打卡(死锁 Lock synchronized与Lock的对比 线程协作 使用线程池)

死锁 多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形。某一个同步块同时拥有“两个以上对象的锁”时,可能会发生“死锁”的问题。 死锁避免方法 产生死锁的四个必要条件: 1.互斥条件:一个资源每次只能被一个进程使用。 2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 3.不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。 4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 上面列

doudoutj的博客 139

lock怎么实现多个线程读_Java多线程学习(六)——Lock的使用

锁是用于通过多个线程控制对共享资源的访问的工具。通常,锁提供对共享资源的独占访问:一次只能有一个线程可以获取锁,并且对共享资源的所有访问都要求首先获取锁。 但是,一些锁可能允许并发访问共享资源,如ReadWriteLock的读写锁。Java5之后并发包中新增了Lock接口以及相关实现类来实现锁功能。 虽然synchronized方法和语句的范围机制使得使用监视器锁更容易编程,并且有助于避免涉及锁...

weixin_39753674的博客 169
上一篇: 浅谈线程安全与sychronized
下一篇: 线程间通信
西红柿丶番茄
博客等级 码龄10年 21粉丝 41原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值