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

如何保证多线程安全

多线程安全的概念

关于安全的判定是指: 在多线程环境下执行的结果, 与在单线程下执行的结果保持一致即可认为是安全的

引发线程不安全的原因

最大的原因就是线程之间的执行顺序是由操作系统随机调度的,此时就会有以下几种情况导致线程不安全

1.可见性: 当涉及到多个线程对同一个数据修改时, 很有可能会导致因为一个线程修改后另外一个线程没拿到数据修改后的值的情况. 这是因为JMM的内存模型导致了这种情况.

2.原子性: 例如执行a++操作时, 是先拿到a的值,再将a+1,然后再将+1后的值赋值给a. 分为这三步. 但线程执行的顺序是随机的(A线程在执行a+1时有可能B线程突然出现执行了a-1). 解决这种问题需要将操作转化成一步就做完中间不能被其他线程插入.

3.有序性: 当线程需要执行的指令很多时, 系统会自动的对这些指令进行顺序上的优化.不会按照写的代码顺序进行执行. 而有时候这种优化会导致线程间的冲突.

解决线程不安全的方法

1.synchronized关键字

synchronized特性:

1.互斥性:进入或使用被synchronized修饰的方法和变量时,相当于是进行了 "'加锁操作". 此时其他线程无法进行操作

2.可重入性: 当一个线程进行了"加锁操作"后, 如果线程出现崩溃等情况时,锁得不到释放,那么其他线程就无法获取到锁了. 这就是"不可重入性".

synchronizd就是可重入锁. 在可重⼊锁的内部, 包含了 "线程持有者" 和 "计数器" 两个信息.
如果某个线程加锁的时候, 发现锁已经被⼈占⽤, 但是恰好占⽤的正是⾃⼰, 那么仍然可以继续到锁,
并让计数器⾃增. 每解一次锁的时候计数器减一. 直到递减为 0 的时候, 才真正释放锁. (才能被别的线程获取到)

synchronized的用法:

//对object对象进行加锁 public class SynchronizedDemo { private Object locker = new Object(); public void method() { synchronized (locker) { } } } //对当前对象进行加锁 public class SynchronizedDemo { public void method() { synchronized (this) { } } } //锁静态方法 public class SynchronizedDemo { public synchronized static void methond() { } }

2.volatile关键字

volatile解决的是"可见性"问题, 其中实现的原理是根据JMM的模型结构来进行操作的:

代码在写入volatile修饰的变量时:

改变工作内存的volatile变量副本的值, 将改变后的副本的值刷新到主内存中代码

在读取volatile修饰的变量时:

从主内存中获取volatile变量的最新值到工作内存中, 再从工作内存中拿到volatile变量的副本

3.使用JUC工具包(java.util.concurrent)

1. ReentrantLock(可重入锁)

ReentrantLock是Lock接口的实现类,功能和Synchronized类似,但支持公平锁 / 非公平锁可中断锁超时获取锁等高级特性。

import java.util.concurrent.locks.ReentrantLock; public class LockCounter { private int count = 0; // 创建可重入锁(默认非公平锁,公平锁传true:new ReentrantLock(true)) private final ReentrantLock lock = new ReentrantLock(); public void increment() { lock.lock(); // 获取锁(必须手动加锁) try { count++; // 核心业务逻辑 } finally { lock.unlock(); // 释放锁(必须放finally,避免异常导致锁泄漏) } } public int getCount() { lock.lock(); try { return count; } finally { lock.unlock(); } } }

ReentrantLock的功能比Synchronized更多, 但必需要自己进行加锁,释放锁.

2.使用Atomic类进行"原子性"操作

import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { // 原子整数:替代int,保证自增/自减的原子性 private final AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); // 原子自增(等价于count++) } public int getCount() { return count.get(); // 原子读取 } }

使用Atomic类的CAS 算法(Compare-And-Swap)实现无锁同步,进行原子性操作性能极高, 适用于简单的数据更新场景

http://www.cnnetsun.cn/news/1324972.html

相关文章:

  • COMSOL随机裂隙双重介质注浆数值模拟
  • 数字化供应链体系建设(PPT)
  • 嵌入式——06 QT
  • 比迪丽LoRA模型Java开发集成指南:SpringBoot后端服务调用
  • React 高德地图进阶技巧:自定义标记、路径动画与主题切换实战
  • RGB 40pin转50pin无源转接板设计与工程实践
  • 不用付费邮箱服务!CloudFlare+163邮箱打造个人专属域名邮箱
  • 避坑指南:STM32F103驱动直流电机时常见的5个硬件设计错误
  • 龙虾地址拼接https://123.207.222.162/#token=
  • 用Qwen3-TTS-12Hz-1.7B-Base打造智能语音客服:完整部署与应用案例
  • League Akari:MOBA玩家的游戏流程自动化与数据驱动解决方案
  • Windows终端神器MobaXterm版本管理全攻略:从下载到卸载避坑指南
  • 别再乱用Mix节点了!Blender混合模式避坑指南:何时该用Multiply而非Darken
  • MGeo中文地址结构化模型部署详解:HTTPS反向代理安全访问配置
  • Phi-3-vision-128k-instruct行业落地:建筑图纸要素提取与合规性初筛案例
  • 告别重复编码:用快马AI快速生成阿卡丽战绩查询工具的高效框架
  • Visionpro单相机标定实战:从9点标定到旋转中心计算的完整流程
  • 从报错到解决:手把手教你处理mosquitto与openssl的依赖关系(含路径检查技巧)
  • Vue开发新姿势!拖拽式组件代码生成器让开发效率翻倍
  • QQ音乐加密音频完全解密指南:如何使用qmcdump工具实现格式转换
  • 新手必看!MedGemma X-Ray医疗AI系统:一键部署教程,快速体验智能影像分析
  • PP-DocLayoutV3详细步骤:text正文区域检测+vertical_text竖排文字方向判别
  • Local AI MusicGen进阶技巧:组合Prompt生成复杂编曲结构
  • [无缝衔接3D工作流] 设计师与工程师的Rhino到Blender无损数据迁移方案
  • 玩客云OneCloud刷机后必装!Docker安装与镜像源优化全攻略(附SSH连接技巧)
  • DASD-4B-Thinking与vLLM集成实战:5步完成AI问答系统部署
  • Phi-3-vision-128k-instruct开源生态:对接LangChain、LlamaIndex插件实践
  • 基于STM32的霜儿-汉服-造相Z-Turbo边缘部署方案:STM32F103C8T6硬件集成
  • 文脉定序系统Node.js后端集成教程:构建高性能排序API服务
  • Creo单位换算实战:从紫铜密度计算到模型质量精准测量