当前位置: 首页 > news >正文

多线程锁

在并发编程中,锁(Lock)是一种用于控制多个线程对共享资源访问的机制。正确使用锁可以确保数据的一致性和完整性,避免出现竞态条件(Race Condition)、死锁(Deadlock)等问题。Java 提供了多种类型的锁来满足不同场景下的需求,从内置的对象锁到更高级别的 java.util.concurrent.locks 包中的显式锁。

为什么需要锁?

当多个线程同时尝试修改同一份数据时,如果没有适当的同步措施,可能会导致以下问题:

  • 数据不一致:不同的线程读取到了部分更新的数据。
  • 丢失更新:一个线程的更改被另一个线程覆盖。
  • 脏读/写:线程读取或写入了尚未完成的操作。

为了解决这些问题,我们需要一种机制来协调线程之间的访问顺序,保证每次只有一个线程能够操作共享资源。这就是锁的作用所在。

Java 中的锁类型

内置锁(Intrinsic Lock)

也称为监视器锁(Monitor Lock),是通过关键字 synchronized 实现的。每个对象都有一个与之关联的内置锁,当一个线程进入由 synchronized 修饰的方法或代码块时,它会自动获取该对象的锁;而当方法执行完毕或遇到 wait() 调用时,则会释放锁。

public synchronized void method() {// 只有一个线程可以进入这里
}
public void method() {synchronized (this) {// 同样只有一个线程可以进入这里}
}

显式锁(Explicit Lock)

从 Java 5 开始,java.util.concurrent.locks 包引入了更为灵活和强大的锁接口——Lock。相比于内置锁,显式锁提供了更多的功能,如可中断的锁等待、超时获取锁以及公平锁等特性。

ReentrantLock

ReentrantLock 是最常用的显式锁实现之一,它允许同一个线程多次获取同一把锁,并且必须按照获取的次数逐一释放。这使得递归调用成为可能。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Counter {private int count = 0;private final Lock lock = new ReentrantLock();public void increment() {lock.lock();try {count++;} finally {lock.unlock(); // 确保无论如何都会解锁}}public int getCount() {return count;}
}
ReadWriteLock

ReadWriteLock 接口定义了一种读写分离的锁机制,其中读锁允许多个线程同时持有,但不允许写锁存在;反之,一旦有线程持有了写锁,其他所有试图获取读锁或写锁的线程都将被阻塞。这种设计非常适合读多写少的情况。

import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class Cache {private final Map<String, Object> map = new HashMap<>();private final ReadWriteLock rwl = new ReentrantReadWriteLock();public Object get(String key) {rwl.readLock().lock();try {return map.get(key);} finally {rwl.readLock().unlock();}}public void put(String key, Object value) {rwl.writeLock().lock();try {map.put(key, value);} finally {rwl.writeLock().unlock();}}
}
StampedLock

StampedLock 是 Java 8 新增的一种乐观锁,它结合了读写锁的功能并提供了更好的性能优化。它支持三种模式:读、写和乐观读。乐观读模式假设不会有冲突发生,因此不会阻塞其他线程;但如果检测到冲突,则需要回滚操作并重新尝试。

import java.util.concurrent.locks.StampedLock;public class Point {private double x, y;private final StampedLock sl = new StampedLock();void move(double deltaX, double deltaY) { long stamp = sl.writeLock();try {x += deltaX;y += deltaY;} finally {sl.unlockWrite(stamp);}}double distanceFromOrigin() { long stamp = sl.tryOptimisticRead();double currentX = x, currentY = y;if (!sl.validate(stamp)) {stamp = sl.readLock();try {currentX = x;currentY = y;} finally {sl.unlockRead(stamp);}}return Math.sqrt(currentX * currentX + currentY * currentY);}
}

锁的使用原则

  • 最小化锁定范围:尽量减少加锁的时间和区域,只保护真正需要保护的资源。
  • 避免死锁:设计时要特别小心,防止形成循环等待链,即多个线程互相持有对方所需的锁。
  • 使用超时机制:对于可能长时间阻塞的操作,考虑设置合理的超时时间以提高系统的健壮性。
  • 优先选择高级并发工具:相比于原始的内置锁,应该更多地利用 java.util.concurrent 包中提供的高级工具,因为它们通常更加安全可靠且易于使用。
  • 文档化锁协议:清晰地记录各个锁之间的关系和使用规则,有助于后续维护人员理解代码逻辑。

最佳实践案例

使用 ReentrantLock 替代内置锁

在某些情况下,ReentrantLock 可以为我们提供比内置锁更多的灵活性。例如,它可以让我们实现非阻塞的锁尝试 (tryLock) 或者带超时的锁等待 (tryLock(long timeout, TimeUnit unit)).

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.TimeUnit;public class BankAccount {private double balance;private final Lock lock = new ReentrantLock();public boolean withdraw(double amount) throws InterruptedException {if (lock.tryLock(1, TimeUnit.SECONDS)) {try {if (balance >= amount) {balance -= amount;return true;}} finally {lock.unlock();}}return false; // 超时未获得锁或余额不足}
}

使用 ReadWriteLock 优化读多写少场景

当应用程序中有大量读操作而写操作相对较少时,ReadWriteLock 可以显著提升性能,因为它允许多个线程同时进行读取,而不必像内置锁那样每次都排他地占用资源。

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;public class ConcurrentCache<K, V> {private final Map<K, V> cache = new ConcurrentHashMap<>();private final ReadWriteLock rwl = new ReentrantReadWriteLock();public V get(K key) {rwl.readLock().lock();try {return cache.get(key);} finally {rwl.readLock().unlock();}}public void put(K key, V value) {rwl.writeLock().lock();try {cache.put(key, value);} finally {rwl.writeLock().unlock();}}
}

使用 StampedLock 进行乐观读

对于那些读操作远多于写操作,并且读操作之间几乎没有竞争的应用程序来说,StampedLock 的乐观读模式可以提供更高的吞吐量。它首先尝试无锁读取,只有在检测到潜在冲突时才会退回到传统的读锁方式。

import java.util.concurrent.locks.StampedLock;public class OptimisticCounter {private long count = 0;private final StampedLock sl = new StampedLock();public long readCount() {long stamp = sl.tryOptimisticRead();long localCount = count;if (!sl.validate(stamp)) {stamp = sl.readLock();try {localCount = count;} finally {sl.unlockRead(stamp);}}return localCount;}public void increment() {long stamp = sl.writeLock();try {count++;} finally {sl.unlockWrite(stamp);}}
}

结语

感谢您的阅读!如果您对多线程锁或其他并发编程话题有任何疑问或见解,欢迎继续探讨。

相关文章:

多线程锁

在并发编程中&#xff0c;锁&#xff08;Lock&#xff09;是一种用于控制多个线程对共享资源访问的机制。正确使用锁可以确保数据的一致性和完整性&#xff0c;避免出现竞态条件&#xff08;Race Condition&#xff09;、死锁&#xff08;Deadlock&#xff09;等问题。Java 提供…...

ZooKeeper 核心知识全解析:架构、角色、节点与应用

1.ZooKeeper 分布式锁怎么实现的 ZooKeeper 是一个高效的分布式协调服务&#xff0c;它提供了简单的原语集来构建更复杂的同步原语和协调数据结构。利用 ZooKeeper 实现分布式锁主要依赖于它的顺序节点&#xff08;Sequential Node&#xff09;特性以及临时节点&#xff08;Ep…...

笔记本电脑 选购 回收 特权模式使用 指南

笔记本电脑 factor 无线网卡&#xff1a;有些笔记本无法检测到特定频段的信息&#xff0c;会导致连不上校园网 sudo iwlist wlp2s0 scan | grep Frequency > net.txt cat net.txt>表示用终端输出覆盖后续文件&#xff0c;>>表示添加到后续文件的末尾 一种更简…...

2023-2024 学年 广东省职业院校技能大赛(高职组)“信息安全管理与评估”赛题一

2023-2024 学年 广东省职业院校技能大赛(高职组“信息安全管理与评估”赛题一&#xff09; 模块一:网络平台搭建与设备安全防护第一阶段任务书任务 1&#xff1a;网络平台搭建任务 2&#xff1a;网络安全设备配置与防护DCRS:DCFW:DCWS:DCBC:WAF: 模块二&#xff1a;网络安全事件…...

C#补充----反射,特性,迭代器,特殊语法,值类型运用类型。

1.反射&#xff1a;通过type 获取类中的数据。创建实例&#xff0c;并赋值。 《1》获取类的方式 《2》反射的应用 <1>获取类型的所有公共成员 <2>获取构造函数 <3>获取类型的 公共成员变量 <4>获取类型的 公共方法 <5>.获取类型的 属性 <6&g…...

深度学习核函数

一、核函数的基本概念 核函数在机器学习中具有重要应用价值&#xff0c;常用于支持向量机&#xff08;SVM&#xff09;等算法中。 核函数是面试中经常被考到的知识点&#xff0c;对于找工作和实际数据转换都有重要作用。 二、数据建模与核函数的作用 数据越多&#xff0c;可…...

Spring MVC流程一张图理解

由于现在项目中大部分都是使用springboot了&#xff0c;但是ssm中的springmvc还是可以了解一下 1 、用户发送请求至前端控制器 DispatcherServlet 。 2 、 DispatcherServlet 收到请求调用 HandlerMapping 处理器映射器。 3 、处理器映射器找到具体的处理器 ( 可以根据 xml 配…...

计算机网络速成

前言&#xff1a;最近在做一些动态的crypto&#xff0c;但是配置总搞不好&#xff0c;正好也有学web的想法&#xff0c;就先学学web再回去做密码&#xff0c;速成视频推荐b站建模老哥 目录 计算机网络概述网络的范围分级电路交换网络&#xff08;电路交换&#xff09;报文交换网…...

spring.profiles.active不同优先级

1、在editConfiguration中配置profiles.activedev会同时影响项目取application-dev.properties、bootstrap-dev.yaml&#xff0c;且这种方式优先级最高&#xff0c;会覆盖application.properties、bootstrap.yaml中的spring.profiles.active配置 2、在application.properties配…...

我这不需要保留本地修改, 只需要拉取远程更改

如果你不需要保留本地修改&#xff0c;只需要拉取远程更改并强制将本地分支与远程分支同步&#xff0c;可以按照以下步骤操作&#xff1a; 1. 丢弃本地修改 首先&#xff0c;丢弃所有本地未提交的修改&#xff1a; git reset --hard这会重置工作目录和暂存区&#xff0c;丢弃…...

源码编译安装httpd 2.4,提供系统服务管理脚本并测试(两种方法实现)

下载 httpd 2.4 源码&#xff1a; wget https://dlcdn.apache.org/httpd/httpd-2.4.x.tar.gztar -zxvf httpd-2.4.x.tar.gzcd httpd-2.4.x配置、编译和安装&#xff1a; ./configure --prefix/usr/local/apache2 --enable-so --enable-ssl --enable-cgi makesudo make install实…...

深度学习在自动化测试中的创新应用:提升运维效率与质量

《深度学习在自动化测试中的创新应用:提升运维效率与质量》 一、引言 在当今快速发展的软件行业中,自动化测试是确保软件质量和可靠性的关键环节。随着软件系统的日益复杂,传统的自动化测试方法在处理复杂场景、提高测试覆盖率和准确性方面面临着诸多挑战。深度学习作为人…...

单独编译QT子模块

单独编译QT子模块 系统 win qt-everywhere-src-5.12.12 下载源码&#xff1a; https://download.qt.io/archive/qt/5.12/5.12.12/single/ 参考&#xff1a; https://doc.qt.io/qt-5/windows-building.html 安装依赖 https://doc.qt.io/qt-5/windows-requirements.html Per…...

学习华为熵减:激发组织活力(系列之三)

目录 为什么学习华为&#xff1f; 学习华为什么&#xff1f; 一、势&#xff1a;顺势而为&#xff0c;在风口上猪都会飞起来。 二、道&#xff1a;就是认识和利用规律层面&#xff0c;文化和制度创新就是企业经营之道。 三、法&#xff1a;就是一套价值管理的变革方法论。…...

CNCF云原生计算基金会

CNCF&#xff0c;全称为云原生计算基金会&#xff08;Cloud Native Computing Foundation&#xff09;&#xff0c;成立于2015年&#xff0c;是一个隶属于Linux基金会的非营利组织。CNCF旨在促进和支持开源技术的发展&#xff0c;特别是那些支持云原生&#xff08;cloud native…...

STM32 FreeRTOS时间片调度---FreeRTOS任务相关API函数---FreeRTOS时间管理

目录 时间片调度简介 FreeRTOS任务相关API函数介绍 延时函数介绍 时间片调度简介 在FreeRTOS中&#xff0c;同等优先级的任务会轮流分享相同的CPU时间&#xff0c;这个时间被称为时间片。在这里&#xff0c;一个时间片的长度等同于SysTick中断的周期。 FreeRTOS任务相关API…...

SQL LAST()

SQL中的LAST()函数是一个用于返回指定列中最后一个记录值的函数。然而&#xff0c;需要注意的是&#xff0c;这个函数并不是SQL标准的一部分&#xff0c;因此并不是所有数据库系统都支持它。具体来说&#xff0c;只有MS Access直接支持LAST()函数【0†source】。 在其他数据库…...

云服务信息安全管理体系认证,守护云端安全

在数据驱动的时代&#xff0c;云计算已成为企业业务的超级引擎&#xff0c;推动着企业飞速发展。然而&#xff0c;随着云计算的广泛应用&#xff0c;信息安全问题也日益凸显&#xff0c;如同暗流涌动下的礁石&#xff0c;时刻威胁着企业的航行安全。这时&#xff0c;云服务信息…...

【Hive】新增字段(column)后,旧分区无法更新数据问题

TOC 【一】问题描述 Hive修改数据表结构的需求&#xff0c;比如&#xff1a;增加一个新字段。 如果使用如下语句新增列&#xff0c;可以成功添加列col1。但如果数据表tb已经有旧的分区&#xff08;例如&#xff1a;dt20190101&#xff09;&#xff0c;则该旧分区中的col1将为…...

C# (图文教学)在C#的编译工具Visual Studio中使用SQLServer并对数据库中的表进行简单的增删改查--14

目录 一.安装SQLServer 二.在SQLServer中创建一个数据库 1.打开SQL Server Manager Studio(SSMS)连接服务器 2.创建新的数据库 3.创建表 三.Visual Studio 配置 1.创建一个简单的VS项目(本文创建为一个简单的控制台项目) 2.添加数据库连接 四.简单连通代码示例 简单连…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

Zustand 状态管理库:极简而强大的解决方案

Zustand 是一个轻量级、快速和可扩展的状态管理库&#xff0c;特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

接口自动化测试:HttpRunner基础

相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具&#xff0c;支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议&#xff0c;涵盖接口测试、性能测试、数字体验监测等测试类型…...

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么&#xff1f;它的作用是什么&#xff1f; Spring框架的核心容器是IoC&#xff08;控制反转&#xff09;容器。它的主要作用是管理对…...

【免费数据】2005-2019年我国272个地级市的旅游竞争力多指标数据(33个指标)

旅游业是一个城市的重要产业构成。旅游竞争力是一个城市竞争力的重要构成部分。一个城市的旅游竞争力反映了其在旅游市场竞争中的比较优势。 今日我们分享的是2005-2019年我国272个地级市的旅游竞争力多指标数据&#xff01;该数据集源自2025年4月发表于《地理学报》的论文成果…...

【深尚想】TPS54618CQRTERQ1汽车级同步降压转换器电源芯片全面解析

1. 元器件定义与技术特点 TPS54618CQRTERQ1 是德州仪器&#xff08;TI&#xff09;推出的一款 汽车级同步降压转换器&#xff08;DC-DC开关稳压器&#xff09;&#xff0c;属于高性能电源管理芯片。核心特性包括&#xff1a; 输入电压范围&#xff1a;2.95V–6V&#xff0c;输…...