多个线程多个锁:如何确保线程安全和避免竞争条件
目录
前言
一、确定需要多个锁的场景
1.独立资源保护
2.部分依赖资源
二、避免死锁
三、锁粒度与并发性能
1. 粗粒度锁定
2.细粒度锁定
四、设计策略:减少资源依赖
1.资源分离
2.无锁设计
3.锁合并
五、Demo讲解
总结:
前言
当多个线程需要操作共享资源时,为了确保数据的一致性和避免竞争条件,通常会使用多个锁来进行同步。这种情况下,如何正确使用多个锁成为一个复杂而关键的问题。下面是一篇十分详细的博客,介绍多线程多锁场景下的最佳实践和注意事项。
一、确定需要多个锁的场景
1.独立资源保护
- 定义:当不同的资源(例如文件、数据库连接等)由不同的锁保护时。
- 示例:一个线程需要读取文件A并写入文件B,而另一个线程读取文件B并写入文件A,这两个操作可以分别使用不同的锁。
2.部分依赖资源
- 定义:多个资源之间存在某种程度的依赖关系,但操作它们的线程可能不会同时访问所有资源。
- 示例:两个线程分别操作两个互相有数据交换的队列,可分别对两个队列加锁,但在交换数据时需要特别小心处理锁的顺序。
二、避免死锁
死锁是多线程编程中常见的问题,特别是在使用多个锁的情况下更容易发生。要避免死锁,可以采取以下策略:
- 按顺序获取锁:对多个资源使用相同的顺序获取锁,以避免循环等待。
- 设置超时时间:在获取锁的过程中设置超时时间,一段时间后未能获取到锁就放弃或重试。
- 使用高级同步工具:比如信号量(Semaphores)或条件变量(Condition Variables),它们提供了更灵活的同步机制,有助于避免死锁。
三、锁粒度与并发性能
1. 粗粒度锁定
- 优点:实现简单,易于理解和维护。
- 缺点:可能导致大量线程等待,从而降低并发性能。
- 示例:一个单一的大锁保护整个资源集合。
2.细粒度锁定
- 优点:提高并发性能,因为锁的范围缩小,减少了线程等待的概率。
- 缺点:实现复杂,需要更精细的设计和管理。
- 示例:为每个独立资源(或资源的部分)使用单独的小锁。
四、设计策略:减少资源依赖
1.资源分离
- 定义:尽量将共享资源划分为独立的部分,使得每个部分只需一个锁。
- 示例:将一个大型数据库拆分为多个独立的部分,每个部分由不同的线程和锁管理。
2.无锁设计
- 定义:通过无锁编程(如使用原子操作)来完全避免锁。
- 示例:使用Java的
AtomicInteger类进行计数器操作。
3.锁合并
- 定义:在某些情况下,将多个锁合并为一个锁,以简化锁管理。
- 示例:如果两个资源总是一起被访问,可以用一个锁来保护它们。
五、Demo讲解
package com.ctb.demo;/*** 关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当做锁* 所以代码中哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock),* * 在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class类)* * @author biao** 2024年*/
public class MyThread2 {private int num =0;public synchronized void printNum(String tag) {try {if (tag.equals("a")) {num=100;System.out.println("tag a,set num over!");Thread.sleep(1000);}else {num = 200;System.out.println("tag b,set num over!");}System.out.println("tag" + tag + "," + "num" + num);} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {final MyThread2 m1 = new MyThread2();final MyThread2 m2 = new MyThread2();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {m1.printNum("a");}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {m2.printNum("b");}});t1.start();t2.start();}}
结果:

package com.ctb.demo;/*** 关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当做锁* 所以代码中哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock),* * 在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class类)* * @author biao** 2024年2月28日-上午12:07:26*/
public class MyThread2 {private static int num =0;// staticpublic static synchronized void printNum(String tag) {try {if (tag.equals("a")) {num=100;System.out.println("tag a,set num over!");Thread.sleep(1000);}else {num = 200;System.out.println("tag b,set num over!");}System.out.println("tag" + tag + "," + "num" + num);} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {final MyThread2 m1 = new MyThread2();final MyThread2 m2 = new MyThread2();Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {m1.printNum("a");}});Thread t2 = new Thread(new Runnable() {@Overridepublic void run() {m2.printNum("b");}});t1.start();t2.start();}}
结果:

总结:
关键字synchronized取得的锁都是对象锁,而不是把一段代码(方法)当做锁
所以代码中哪个线程先执行synchronized关键字的方法,哪个线程就持有该方法所属对象的锁(Lock),
在静态方法上加synchronized关键字,表示锁定.class类,类一级别的锁(独占.class类)
相关文章:
多个线程多个锁:如何确保线程安全和避免竞争条件
目录 前言 一、确定需要多个锁的场景 1.独立资源保护 2.部分依赖资源 二、避免死锁 三、锁粒度与并发性能 1. 粗粒度锁定 2.细粒度锁定 四、设计策略:减少资源依赖 1.资源分离 2.无锁设计 3.锁合并 五、Demo讲解 总结: 前言 当多个线程需要…...
Linux-笔记 设备树插件
目录 前言: 设备树插件的书写规范: 设备树插件的编译: 内核配置: 应用背景: 举例: 前言: 设备树插件(Device Tree Blob Overlay,简称 DTBO)是Linux内核和嵌入式系统…...
【排序算法】总结篇
✨✨这些 排序算法都是指的 需要进行比较的排序算法 ✨✨下面都是略微讲解一下思路,如果需要详细了解哪一个排序,点击👉链接即可 ✨✨对于时间、空间复杂度、稳定性,希望你🧑🎓能够理解记忆🧑…...
鸿蒙开发文件管理:【@ohos.fileio (文件管理)】
文件管理 该模块提供文件存储管理能力,包括文件基本管理、文件目录管理、文件信息统计、文件流式读写等常用功能。 说明: 本模块首批接口从API version 6开始支持。后续版本的新增接口,采用上角标单独标记接口的起始版本。 导入模块 impor…...
硬件工程师学习规划
背景介绍 当前电子行业中,互联网因为中国人口基数大,得到很快的发展,一越成为世界第一梯队,互联网软件薪资要高于传统制造业硬件的薪资,从各大招聘软件上就能看到,那么为什么软件发展要好于硬件࿱…...
esp32 8行代码实现蓝牙音响
目录 硬件准备: 具体代码: 接线: 备注: 八行代码实现简易版蓝牙音响,亲测有效: esp32 DIY蓝牙音响_哔哩哔哩_bilibili 硬件准备: ESP32-wroom、MAX98357音频放大器模块、4欧3瓦小喇叭、杜…...
注册用户如何防止缓存穿透?
注册用户如何防止缓存穿透? 先说明用户注册为什么会发送缓存穿透:用户注册时,需要验证用户名是否已存在,先查缓存,没有再查数据库,还没有才验证通过。高并发的情况下就可能有大量用户同时注册,…...
Presto基础知识
Presto缓存 引入Presto缓存之前 BackgroundHiveSplitLoader 使用底层的文件系统直接进行数据的读写; 引入Presto缓存机制之后,底层的文件系统被被CachingFileSystem 代理一层 CachingFileSystem 有两个子类,根据你选用的底层缓存引擎的不同…...
Ajax + Easy Excel 通过Blob实现导出excel
前端代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><script src"./js/jquery-3.6.0.min.js"></script></head><body><div><button onclick"exportF…...
Qt+qss动态属性改变控件状态切换的样式
先说点基础的吧,qt的样式实现,常见的主要有三种方式,分别为: 1.ui界面中右键样式表直接添加 2.代码中对控件设置样式setStyleSheet 3.外部预设好qss文件,代码中加载后设置样式 实际工作开发中,我推荐使用优…...
纷享销客安全体系:安全运维运营
安全运维运营(Security Operations,SecOps)是指在信息安全管理中负责监控、检测、响应和恢复安全事件的一系列运营活动。它旨在保护组织的信息系统和数据免受安全威胁和攻击的损害。 通过有效的安全运维运营,组织可以及时发现和应对安全威胁,减少安全事…...
富瀚微FH8322 ISP图像调试—BLC校正
1、简单介绍 目录 1、简单介绍 2、调试方法 3、输出结果 富瀚微平台调试有一段时间了,一直没有总结,我们调试ISP的时候,首先一步时确定好sensor的黑电平值,黑电平如果不准,则会影响到后面的颜色及对比度相关模块。…...
什么是大型语言模型 ?
引言 在本文[1]中,我们将从高层次概述大型语言模型 (LLM) 的具体含义。 背景 2023年11月,我偶然间听闻了OpenAI的开发者大会,这个大会展示了人工智能领域的革命性进展,让我深深着迷。怀着对这一领域的浓厚兴趣,我加入了…...
RocketMq详解:二、SpringBoot集成RocketMq
在上一章中我们对Rocket的基础知识、特性以及四大核心组件进行了详细的介绍,本章带着大家一起去在项目中具体的进行应用,并设计将其作为一个工具包只提供消息的分发服务和业务模块进行解耦 在进行本章的学习之前,需要确保你的可以正常启动和…...
【源码】二开版微盘交易系统/贵金属交易平台/微交易系统
二开版微盘交易系统/贵金属交易平台/微交易系统 一套二开前端UI得贵金属微交易系统,前端产品后台可任意更换 此系统框架不是以往的至尊的框架,系统完美运行,K线采用nodejs方式运行 K线结算都正常,附带教程 资源来源:https://www.…...
React@16.x(26)useContext
目录 1,上下文的使用2,useContext 1,上下文的使用 之前的文章中介绍过 context上下文。 使用举例: import React, { useState } from "react";const ctx React.createContext();function Child() {return <ctx.C…...
Vue2学习(04)
目录 一、组件的三大组成部分 二、组件的样式冲突scoped 三、scoped原理 编辑 四、data是一个函数 五、组件通信 1.概念:是指组件与组件之间的数据传递,组件的数据是独立的,无法直接访问其他组件的数据,想用其他组件的数…...
Python中columns()函数
1. columns的概念 在数据分析和处理中,columns是指数据表中的列,也称为字段。每一列代表了特定类型的数据,在一个数据表中,每一行代表了一个数据实例,而每一列则代表了一个特定的特征或属性。 可以直接定义和更改列标题,也可以直接读取某列的数据,或者对某列进行运算。…...
Vue3 使用 vue-clipboard3 实现一键复制
安装依赖 npm install --save vue-clipboard3示例 <template><el-input v-model"data"></el-input><button click"touchCopy">复制链接</button> </template><script setup lang"ts"> // 导入插件 …...
人机环境生态系统智能的流动性
一般来说,流动性可以理解为事物在空间或时间上的转移、变化或运动。在人机环境生态系统中,流动性可以涉及以下几个方面: 信息流动:数据、消息、知识等在系统中的传递和交换。这可能包括传感器收集的数据传输到处理中心,…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!
5月28日,中天合创屋面分布式光伏发电项目顺利并网发电,该项目位于内蒙古自治区鄂尔多斯市乌审旗,项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站,总装机容量为9.96MWp。 项目投运后,每年可节约标煤3670…...
leetcodeSQL解题:3564. 季节性销售分析
leetcodeSQL解题:3564. 季节性销售分析 题目: 表:sales ---------------------- | Column Name | Type | ---------------------- | sale_id | int | | product_id | int | | sale_date | date | | quantity | int | | price | decimal | -…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...
