多个线程多个锁:如何确保线程安全和避免竞争条件
目录
前言
一、确定需要多个锁的场景
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"> // 导入插件 …...
人机环境生态系统智能的流动性
一般来说,流动性可以理解为事物在空间或时间上的转移、变化或运动。在人机环境生态系统中,流动性可以涉及以下几个方面: 信息流动:数据、消息、知识等在系统中的传递和交换。这可能包括传感器收集的数据传输到处理中心,…...
VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP
编辑-虚拟网络编辑器-更改设置 选择桥接模式,然后找到相应的网卡(可以查看自己本机的网络连接) windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置,选择刚才配置的桥接模式 静态ip设置: 我用的ubuntu24桌…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
