19. Java 并发锁之 Lock 接口

1. 前言

本节内容主要是对 Java 并发锁之 Lock 接口进行介绍,Lock 是类似于 synchronized 的另外一种锁的使用,那么本节我们会对 Lock 进行详细的介绍,主要知识点如下:

  • Lock 接口的介绍,这是我们开始认识 Lock 的敲门砖,本节课程的基础知识;
  • Lock 接口相比于 synchronized 关键字的优点,这也是我们学习 Lock 接口的意义所在;
  • Lock 接口的常用方法介绍,了解 Lock 接口中的常用方法,是本节内容的核心知识点。

Lock 是一个接口,并非一个实现类,本节内容主要对 Lock 接口进行一个意义、结构及方法的介绍,为后续讲解 Lock 接口的实现类常用锁奠定一个扎实的基础。

2. Lock 接口的介绍

Lock 接口的诞生:在 Java 中锁的实现可以由 synchronized 关键字来完成,但在 Java5 之后,出现了一种新的方式来实现,即 Lock 接口。

诞生的意义:Lock 接口支持那些语义不同(重入、公平等)的锁规则,可以在非阻塞式结构的上下文(包括 hand-over-hand 和锁重排算法)中使用这些规则。主要的实现是 ReentrantLock。对于 ReentrantLock,后续有专门的小节进行讲解。

JDK 1.5 前的 synchronized:在多线程的情况下,当一段代码被 synchronized 修饰之后,同一时刻只能被一个线程访问,其他线程都必须等到该线程释放锁之后才能有机会获取锁访问这段代码。

Lock 接口: 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的 Condition 对象。

Lock 相对于 synchronized 关键字而言更加灵活,你可以自由得选择你想要加锁的地方。当然更高的自由度也带来更多的责任。

使用示例:我们通常会在 try catch 模块中使用 Lock 关键字,在 finally 模块中释放锁。

	 Lock lock = new ReentrantLock(); //通过子类进行创建,此处以ReentrantLock进行举例
     lock.lock(); //加锁
     try {
         // 对上锁的逻辑进行操作
     } finally {
         lock.unlock(); //释放锁
     }

3. Lock 接口与 synchronized 关键字的区别

  • 实现:synchronized 关键字基于 JVM 层面实现,JVM 控制锁的获取和释放。Lock 接口基于 JDK 层面,手动进行锁的获取和释放;
  • 使用:synchronized 关键字不用手动释放锁,Lock 接口需要手动释放锁,在 finally 模块中调用 unlock 方法;
  • 锁获取超时机制:synchronized 关键字不支持,Lock 接口支持;
  • 获取锁中断机制:synchronized 关键字不支持,Lock 接口支持;
  • 释放锁的条件:synchronized 关键字在满足占有锁的线程执行完毕,或占有锁的线程异常退出,或占有锁的线程进入 waiting 状态才会释放锁。Lock 接口调用 unlock 方法释放锁;
  • 公平性:synchronized 关键字为非公平锁。Lock 接口可以通过入参自行设置锁的公平性。

4. Lock 接口相比 synchronized 关键字的优势

我们通过两个个案例分析来了解 Lock 接口的优势所在。
案例 1 :在使用 synchronized 关键字的情形下,假如占有锁的线程由于要等待 IO 或者其他原因(比如调用 sleep 方法)被阻塞了,但是又没有释放锁,那么其他线程就只能一直等待,别无他法。这会极大影响程序执行效率。

案例 1 分析:该案例体现了 synchronized 的缺陷,当线程被占有时,其他线程会陷入无条件的长期等待。这是非常可怕的,因为系统资源有限,最终可能导致系统崩溃。

案例 1 解决:Lock 接口中的 tryLock (long time, TimeUnit unit) 方法或者响应中断 lockInterruptibly () 方法,能够解决这种长期等待的情况。

案例 2 :我们知道,当多个线程读写文件时,读操作和写操作会发生冲突现象,写操作和写操作也会发生冲突现象,但是读操作和读操作不会发生冲突现象。
但是如果采用 synchronized 关键字实现同步的话,就会导致一个问题,即当多个线程都只是进行读操作时,也只有一个线程可以进行读操作,其他线程只能等待锁的释放而无法进行读操作。

案例 2 分析:该案例体现了 synchronized 的缺陷,悲观锁的缺陷。我们说过,如果只是读操作,没有增删改操作的话,多线程环境下无需加锁。但是这种情况下,如果在同一时间多个线程进行读操作,synchronized 会 block 其他的读操作,这是不合理的。

案例 2 解决:Lock 接口家族也可以解决这种情况,后续我们会对 ReadWriteLock 接口的一个子类 ReentrantReadWriteLock 进行讲解。

总结:Lock 接口实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作,能够解决 synchronized 不能够避免的问题。

5. Lock 接口的常用方法

我们来简单的看下,JDK 中 Lock 接口的源码中所包含的方法:

public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}

方法介绍

  1. void lock():获取锁。如果锁不可用,出于线程调度目的,将禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态;
  2. void lockInterruptibly():如果当前线程未被中断,则获取锁;
  3. boolean tryLock():仅在调用时锁为空闲状态才获取该锁。如果锁可用,则获取锁,并立即返回值 true。如果锁不可用,则此方法将立即返回值 false;
  4. boolean tryLock(long time, TimeUnit unit):如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁;
  5. void unlock():释放锁。在等待条件前,锁必须由当前线程保持。调用 Condition.await () 将在等待前以原子方式释放锁,并在等待返回前重新获取锁;
  6. Condition newCondition():返回绑定到此 Lock 实例的新 Condition 实例。

Tips:对 Lock 接口方法的使用,我们必须基于子类进行 Lock 的创建来展示,由于目前我们还未接触 Lock 接口的实现子类,此处只做方法的介绍。后续对 ReentrantLock 进行讲解时,会进行深入讲解。

6. 小结

本节主要是对 Lock 接口的常用方法进行了介绍,为本节内容的核心知识。除了方法的介绍外,本节内容不容忽视的一个重点内容是 synchronized 关键字与 Lock 接口的区别,以及 Lock 接口的优势所在。

掌握本节内容,有助于同学对后续实现类锁的学习,为后续的学习奠定了良好的基础。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/773739.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot AOP面向切面编程 基础

介绍 在 Spring Boot 中&#xff0c;AOP&#xff08;面向切面编程&#xff09;是一种强大的技术&#xff0c;它允许你在应用程序中横切关注点&#xff0c;比如日志记录、事务管理、性能监控等&#xff0c;从而避免重复代码和混乱 可以记录操作日志 权限控制 。 依赖 <dep…

HTMLCSS(入门)

HTML <html> <head><title>第一个页面</title></head><body>键盘敲烂&#xff0c;工资过万</body> </html> <!DOCTYPE>文档类型声明&#xff0c;告诉浏览器使用哪种HTML版本显示网页 <!DOCTYPE html>当前页面采取…

go语言day08 泛型 自定义错误处理 go关键字:协程

泛型&#xff1a; 抛错误异常 实现error接口类型 用java语言解释的话&#xff0c;实现类需要重写error类型的抽象方法Error().这样就可以自定义异常处理。 回到go语言&#xff0c;在Error()方法中用*argError 这样一个指针类来充当error接口的实现类。 在f2()方法中定义返回值…

本地部署秘塔开源搜索引擎

秘塔AI搜索是由秘塔科技于2024年初推出的一款新型搜索引擎&#xff0c;被业界誉为“中国版的Perplexity”。秘塔科技成立于2018年4月&#xff0c;其核心团队包括CEO闵可锐、技术专家唐悦和首席运营官王益为等。秘塔AI搜索以其高效简洁的特点受到关注&#xff0c;其搜索结果直接…

累积分布函数的一些性质证明

性质1&#xff1a; E [ X ] ∫ 0 ∞ ( 1 − F ( x ) ) d x − ∫ − ∞ 0 F ( x ) d x ( 1 ) E[X]\int_0^{\infty}(1-F(x))dx - \int_{-\infty}^0F(x)dx\quad (1) E[X]∫0∞​(1−F(x))dx−∫−∞0​F(x)dx(1) 证明&#xff1a; E [ X ] ∫ − ∞ ∞ x p ( x ) d x E[X] …

ETCD 基本介绍与常见命令的使用

转载请标明出处&#xff1a;https://blog.csdn.net/donkor_/article/details/140171610 文章目录 一、基本介绍1.1 参考1.2 什么是ETCD1.3 ETCD的特点1.4 ETCD的主要功能1.5 ETCD的整体架构1.6 什么时候用ETCD&#xff0c;什么时候用redis 二、安装三、使用3.1 etcdctl3.2 常用…

审核平台前端新老仓库迁移

背景 审核平台接入50业务&#xff0c;提供在线审核及离线质检、新人培训等核心能力&#xff0c;同时提供数据报表、资源追踪、知识库等工具。随着平台的飞速发展&#xff0c;越来越多的新业务正在或即将接入审核平台&#xff0c;日均页面浏览量为百万级别。如今审核平台已是公司…

[Redis]哨兵机制

哨兵机制概念 在传统主从复制机制中&#xff0c;会存在一些问题&#xff1a; 1. 主节点发生故障时&#xff0c;进行主备切换的过程是复杂的&#xff0c;需要人工参与&#xff0c;导致故障恢复时间无法保障。 2. 主节点可以将读压力分散出去&#xff0c;但写压力/存储压力是无法…

直击园区消防管理现状,智慧消防相比传统消防管理的优势是什么

一、工业园区消防管理现状 1、消防信息智能化程度低 信息化手段落后&#xff0c;现场的数据信息无法即时传送至指挥中心&#xff0c;突发事件发生时&#xff0c;无法扁平化指挥到基层现场&#xff0c;应急处置能力不足。 2、防控体系不健全 存在监测盲点&#xff0c;火灾报警…

Mybatis实现RBAC权限模型查询

RBAC权限模型 Role-Based Access Control&#xff0c;中文意思是&#xff1a;基于角色&#xff08;Role&#xff09;的访问控制。这是一种广泛应用于计算机系统和网络安全领域的访问控制模型。 简单来说&#xff0c;就是通过将权限分配给➡角色&#xff0c;再将角色分配给➡用…

ABB机器人坐标系偏移指令

ABB机器人在坐标系中偏移用到的指令有&#xff1a;Offs和RelTool。Offs用在工件坐标系中偏移&#xff0c;而RelTool是在工具坐标系中偏移。 一、Offs用于在一个机械臂位置的工件坐标系中添加一个偏移量。 Offs (Point &#xff0c;XOffset&#xff0c; YOffset &#xff0c;Z…

【UE5.1】Chaos物理系统基础——05 蓝图绑定Chaos破裂或碰撞事件

步骤 1. 新建一个父类为Actor的蓝图&#xff0c;这里命名为“BP_ChaosExplosionEvent” 打开“BP_ChaosExplosionEvent”&#xff0c;添加一个变量&#xff0c;这里命名为“GC”&#xff0c;变量类型为“几何体集actor”&#xff0c;设置为可编辑实例 在事件图表中添加如下节点…

Unity休闲手机游戏开发课程

课程介绍 Unity休闲手机游戏开发课程将教您如何利用Unity游戏引擎创建令人愉快的休闲手机游戏。从基础的游戏开发知识到高级的游戏制作技巧&#xff0c;您将学习到创建各种类型的休闲游戏所需的关键技能和工具。无论您是初学者还是有一定经验的开发者&#xff0c;本课程都能帮助…

基于JavaScript、puppeteer的爬虫

前期准备: npm puppeteer import puppeteer from puppeteer; puppeteer文档 第一步&#xff1a;启动浏览器&#xff0c;跳转到需要爬取的页面 const browser await puppeteer.launch({ headless: false });const page await browser.newPage();await page.goto(url, { w…

ssm高校宿舍用电管理系统-计算机毕业设计源码97859

摘要 随着高校规模的扩大和学生数量的增加&#xff0c;高校宿舍的用电需求也日益庞大。为了提高用电效率、节约能源、确保用电安全和方便管理&#xff0c;开发一个高校宿舍用电管理系统具有重要意义。本系统将采用Java作为后端开发语言&#xff0c;具备跨平台特性&#xff0c;能…

收银系统源码-营销活动-幸运抽奖

1. 功能描述 营运抽奖&#xff1a;智慧新零售收银系统&#xff0c;线上商城营销插件&#xff0c;商户/门店在小程序商城上设置抽奖活动&#xff0c;中奖人员可内定&#xff1b; 2.适用场景 新店开业、门店周年庆、节假日等特定时间促销&#xff1b;会员拉新&#xff0c;需会…

k8s-第四节-Service

Service Service 通过 label 关联对应的 PodServcie 生命周期不跟 Pod 绑定&#xff0c;不会因为 Pod 重创改变 IP提供了负载均衡功能&#xff0c;自动转发流量到不同 Pod可对集群外部提供访问端口集群内部可通过服务名字访问 创建 Service kubectl apply -f service.yamlkub…

多个comfyui之间如何共享模型,节省存储空间

COMFYUI 模型共享插件教程 一、COMFYUI 模型共享插件教程1.1 插件特性1.2 插件介绍1.3 链接 二、详细配置步骤2.1 开启开发者选项2.2 放置插件文件2.3 放置配置文件2.4 编辑配置文件2.4.1 其他配置项 三、启动COMFYUI并验证3.1 启动COMFYUI3.2 验证模型共享3.3 多整合包共享配置…

C++11|完美转化 新的类功能 可变参数模板

目录 一、完美转发 1.1模板中的&&万能引用 1.2完美转发 1.3完美转发实际中的引用场景 二、新的类功能 2.1移动构造和移动赋值规则详解 2.2类成员变量初始化和强制生成默认函数(default) 2.3禁止生成默认函数的关键字(delete) 三、可变参数模板 3.1递归函数方式…

TCP和IP数据包结构

一、问题引入 一般我们在谈上网速度的时候&#xff0c;专业上用带宽来描述&#xff0c;其实无论说网速或者带宽都是不准确的&#xff0c;呵呵。比如&#xff1a;1兆&#xff0c;512K……有些在学校的学生&#xff0c;也许会有疑问&#xff0c;明明我的业务是1M&#xff0c;为…