Java中的锁(一)
一、前言
在Java中,锁是用于多线程同步的重要概念。它可以保护共享资源,确保多个线程在访问共享资源时的数据一致性。
共享资源指的是多个线程同时对同一份资源进行访问 (读写操作),被多个线程访问的资源就称为共享资源。 如何保证多个线程访问到的数据是一致的 ,则被称为数据同步或者资源同步 。
线程同步是指在多线程编程中,为了保证多个线程按照某种特定的方式正确、有序地执行,需要进行线程间的协作与同步。在多线程编程中,当多个线程共享同一份资源时,由于线程的执行顺序是不确定的,因此会存在一些并发问题(线程不安全问题),如死锁、数据不一致、竞态条件等问题。为了避免这些问题,需要对线程进行同步。线程同步实际上就是通过线程之间的协作,使得线程能够按照一定的顺序来访问共享资源,从而避免并发问题的发生。常用的线程同步方式有互斥锁、读写锁、信号量、条件变量等。
二、Java中锁的概念
在Java中,锁主要用来解决多线程并发访问共享资源的问题;可能存在的并发问题(线程不安全问题):
1、死锁(Deadlock)
当多个线程同时持有某些资源的锁,并且彼此都在等待对方释放资源的锁时,就会发生死锁。这时,线程无法继续执行,造成系统的停滞。
2、数据不一致性(Data Inconsistency)
当多个线程同时对共享数据进行读写操作,并且它们之间缺少同步机制时,可能导致数据不一致。例如,一个线程正在修改某个对象的属性值,而另一个线程正在读取该属性值,由于缺乏同步,读取到的值可能是不正确或不一致的。
3、竞态条件(Race Condition)
当多个线程对共享数据进行读写操作,并且执行的顺序会影响最终结果时,就可能发生竞态条件。例如,多个线程同时对一个变量进行自增操作,由于不可预知的执行顺序,最终结果可能与期望不符。
4、非原子性操作(Non-atomic Operation)
某些操作在执行过程中不是原子性的,即不能一次性完成,而需要多个步骤。如果多个线程同时执行这样的操作,就可能导致不一致的结果。例如,在多线程环境下对int类型变量进行自增操作,由于该操作涉及两个步骤(读取和写入),可能产生不正确的结果。
5、资源争用(Resource Contention)
多个线程同时竞争同一份资源,导致资源的使用效率下降,总体性能降低。
6、饥饿(Starvation)
某些线程可能因为无法获取资源而一直等待,导致无法正常执行,进而影响整个程序的性能。
三、线程同步的方式
1、互斥锁(Mutex):
互斥锁(又名互斥量)强调的是资源之间的访问互斥:每个线程在对共享资源操作前都会尝试先加锁,加锁成功才能操作,操作结束之后释放锁。
某个线程对互斥量加锁后,任何其他试图再对互斥量加锁的线程都将被阻塞直到当前线程释放该互斥锁。如果释放互斥锁时有多个线程阻塞,所有在该互斥锁上的阻塞线程都会变成可运行状态。第一个变成运行状态的线程可以对互斥量加锁,其余线程将会看到互斥量依然被锁住,只能回去再次等待它重新变为可用。
2、读写锁(Read-Write Lock):
读写锁和互斥量类似,是另一种实现线程同步的方式,但是它将操作分为读、写两种方式,可以多个线程同时占用读模式,这样使得读写锁具有更高的并行性。相较于互斥锁而言读写锁有一定的性能提升,应对的是单写多读模型:
- 写独占:写锁占用时,其他线程加读锁或者写锁时都会阻塞(并非失败)
- 读共享:读锁占用时,其他线程加写锁时会阻塞,加读锁会成功
3、条件变量(Condition Variable):
条件变量本质上也是一个多线程间共享的全局变量,它的功能是阻塞线程,被阻塞的线程直到接收到“条件成立”的信号后才能继续执行。
需要注意的是:
- 条件变量并不是锁(但它几乎总是和互斥量一起使用的),而是线程间的一种通讯机制
- 条件变量本身也不包含条件,它被称为条件变量是因为它经常和条件语句(if/while)一起使用
4、信号量(Semaphore):
使用信号量来控制多个线程对有限数量资源的访问。信号量表示资源的数量,每个线程在使用完资源后必须释放信号量,以便其他线程可以使用资源。
信号量分为有名信号量和无名信号量,无名信号量用于线程同步,有名信号量一般用于进程之间管理。
信号量本质上是一个非负的整数计数器,用于控制公共资源的访问,也被称为PV原子操作:
- P操作:即信号量sem减一,若sem小于等于0则P操作被阻塞,直到sem变量大于0为止
- V操作:即信号量sem加一
四、锁的基本原理
锁的基本原理是防止竞争条件,保证线程安全性和可见性,避免死锁等问题。下面是关于锁的基本原理的介绍:
1、防止竞争条件
当多个线程同时访问共享资源时,可能会发生竞争条件。竞争条件是指当多个线程同时执行同一段代码时,由于执行顺序的不同而导致结果的不确定性。
锁的作用就是在多个线程访问共享资源时保证同一时刻只有一个线程访问,从而避免竞争条件的发生。当一个线程获取到锁时,其他线程必须等待锁的释放才能继续访问共享资源。
2、保证线程安全性和可见性
线程安全性和可见性是Java并发编程中非常重要的概念。线程安全性是指当多个线程同时访问共享资源时,不会出现数据损坏或程序崩溃等问题。可见性是指当一个线程修改了共享资源时,其他线程能够立即看到这个修改。
锁机制可以保证线程安全性和可见性。当一个线程获取到锁时,其他线程无法修改共享资源,从而避免了数据损坏和程序崩溃等问题。而锁机制也可以保证共享资源的可见性,因为当一个线程释放锁时,其他线程能够立即看到共享资源的最新状态。
3、避免死锁
死锁是指两个或多个线程相互等待对方释放锁,从而导致程序无法继续执行的情况。死锁是Java并发编程中一个非常严重的问题,必须避免发生。
为了避免死锁,必须采取一些策略,例如避免嵌套锁、避免长时间占用锁、按照相同的顺序获取锁等。另外,还可以使用专门的工具来检测和避免死锁,例如死锁检测器和避免死锁算法等。
总之,锁机制是Java并发编程中非常重要的一部分,了解锁的基本原理,包括如何防止竞争条件、如何保证线程安全性和可见性,以及如何避免死锁等问题,对于编写高效、可靠的并发程序非常有帮助。
相关文章:
Java中的锁(一)
一、前言 在Java中,锁是用于多线程同步的重要概念。它可以保护共享资源,确保多个线程在访问共享资源时的数据一致性。 共享资源指的是多个线程同时对同一份资源进行访问 (读写操作),被多个线程访问的资源就称为共享资源。 如何保证多个线程访…...

CSS-SVG-环形进度条
线上代码地址 <div class"circular-progress-bar"><svg><circle class"circle-bg" /><circle class"circle-progress" style"stroke-dasharray: calc(2 * 3.1415 * var(--r) * (var(--percent) / 100)), 1000" …...

英语中修饰头发的形容词顺序是怎么样的(加补充)
一、英语描述发型 :漂亮长短形状颜色头发。 例如她有一头美丽的黑色的直发。She has beautiful long straight black hair.二、多个形容词修饰同一名词时的顺序是固定的,其顺序为:①冠词、指示代词、不定代词、物主代词②序数词基数词③一般性描绘形容词…...
python的WebSocket编程详解,案例群聊系统实现
1.websocket相关 1.1为什么要用websocket 如果有需求要实现服务端向客户端主动推送消息时(比如聊天室,群聊室)有哪几种方案 轮训:让浏览器每隔两秒发送一次请求,缺点:有延时,请求太多网站压力…...
flutter学习-day22-使用GestureDetector识别手势事件
文章目录 1. 介绍2. 使用2-1. 单击双击和长按2-2. 拖动和滑动2-3. 缩放 3. 注意点 1. 介绍 在 flutter 中,GestureDetector 是手势识别的组件,可以识别点击、双击、长按、拖动、缩放等手势事件,并且可以与子组件进行交互,构造函数…...

uni-app tabbar组件
锋哥原创的uni-app视频教程: 2023版uniapp从入门到上天视频教程(Java后端无废话版),火爆更新中..._哔哩哔哩_bilibili2023版uniapp从入门到上天视频教程(Java后端无废话版),火爆更新中...共计23条视频,包括:第1讲 uni…...

【Midjourney】Midjourney根据prompt提示词生成人物图片
目录 🍇🍇Midjourney是什么? 🍉🍉Midjourney怎么用? 🔔🔔Midjourney提示词格式 Midjourney生成任务示例 例1——航空客舱与乘客 prompt prompt翻译 生成效果 大图展示 细节大…...

Oracle 拼接字符串
语法 使用||拼接如果内容中有单引号,则可在该单引号前面再加一个单引号进行转义 例子 比如有一个业务是根据需要生成多条插入语句 select insert into des_account_des_role(des_account_id, roles_id) values( || id || , || (select id from des_role where wo…...
探究公有云中的巨人:深入分析大数据产品的架构设计
目录 一、服务器分类 二、公有云基础和产品 网络 vpc专有网络 弹性公网IP(Elastic IP)...

亚马逊云科技 re:Invent 2023 产品体验:亚马逊云科技产品应用实践 王炸产品 Amazon Q,你的 AI 助手
意料之中 2023年9月25日,亚马逊宣布与 Anthropic 正式展开战略合作,结合双方在更安全的生成式 AI 领域的先进技术和专业知识,加速 Anthropic 未来基础模型的开发,并将其广泛提供给亚马逊云科技的客户使用。 亚马逊云科技开发者社…...

并发编程大杀器,京东多线程编排工具asyncTool
一、简介 并发编程大杀器,京东多线程编排工具asyncTool,可以解决任意的多线程并行、串行、阻塞、依赖、回调的并行框架,可以任意组合各线程的执行顺序,带全链路执行结果回调。多线程编排一站式解决方案。 二、特点 多线程编排&am…...

【开源项目】智慧交通~超经典开源项目实景三维数字孪生高速
数字孪生高速运营管理平台,以提升高速公路管理水平和方便出行为主要目标,充分利用云计算、AI、大数据等,实现对高速公路控制、指挥、运营的智能化。飞渡科技以实景三维数据为基础,基于大数据、高分遥感、数据分析以及数据融合等前…...

udp多播/组播那些事
多播与组播 多播(multicast)和组播(groupcast)是相同的概念,用于描述在网络中一对多的通信方式。在网络通信中,单播(unicast)是一对一的通信方式,广播(broad…...

C++ Qt开发:SqlRelationalTable关联表组件
Qt 是一个跨平台C图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍SqlRelationalTable关联表组件的常用方法及灵…...

【LeetCode】修炼之路-0001-Two Sum(两数之和)【python】【简单】
前言 计算机科学作为一门实践性极强的学科,代码能力的培养尤为重要。当前网络上有非常多优秀的前辈分享了LeetCode的最佳算法题解,这对于我们这些初学者来说提供了莫大的帮助,但对于我这种缺乏编程直觉的学习者而言,这往往难以消化吸收。(为什么别人就能想出这么优雅…...

秋招复习篇之代码规范
目录 前言 1、变量命名 2、代码空格 1)操作符左右一定有空格, 2)分隔符(, 和;)前一位没有空格,后一位保持空格,例如: 3)大括号和函数保持同一行,并有一个空格…...
Docker:登录私有仓库\退出私有仓库
一、登录仓库 docker login : 登录到一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub 语法: docker login [OPTIONS] [SERVER] docker login -u 用户名 -p 密码 仓库名称 # 登入私有仓库 [rootlocalhost ~]# docker login --…...

与擎创科技共建一体化“数智”运维体系,实现数字化转型
小窗滴滴小编获取最新版公司简介 前言: 哈喽大家好,最近分享的互联网IT热讯大家都挺喜欢,小编看着数据着实开心,感谢大家支持,小编会继续给大家推送。 新岁即将启封,我们一年一期的运维干货年末大讲也要…...

开放网络+私有云=?星融元的私有云承载网络解决方案实例
在全世界范围内的云服务市场上,开放网络一直是一个备受关注的话题。相比于传统供应商的网络设备,开放网络具备软硬件解耦、云原生、可选组件丰富等优势,对云服务商和超大型企业有足够的吸引力。 SONiC作为开源的网络操作系统,使得…...

【Linux学习笔记】Linux下nginx环境搭建
1、下载nginx 安装rpm命令: rpm ivh nginx-release.rpm。(直接使用linux命令下载wget http://nginx.org/packages/rhel/6/noarch/RPMS/nginx-release-rhel-6-0.el6.ngx.noarch.rpm 2、设置nginx开机启动 chkconfig nginx on 3、开启nginx服务 方法一:service nginx…...

19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...

51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
HTML前端开发:JavaScript 常用事件详解
作为前端开发的核心,JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例: 1. onclick - 点击事件 当元素被单击时触发(左键点击) button.onclick function() {alert("按钮被点击了!&…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...

tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...
SpringAI实战:ChatModel智能对话全解
一、引言:Spring AI 与 Chat Model 的核心价值 🚀 在 Java 生态中集成大模型能力,Spring AI 提供了高效的解决方案 🤖。其中 Chat Model 作为核心交互组件,通过标准化接口简化了与大语言模型(LLM࿰…...