线程安全问题的产生原因与解决方案

线程学习java过程中较难搬动的大山之一,但山再高总会搬完,路再远也总会走到。此篇是线程安全问题产生的原因与解决方案阐述,且看我慢慢"搬山"。

一.线程安全问题产生原因

1. 线程安全产生的根本原因是操作系统对线程的调度是随机的,线程是抢占式执行的;2.当多个线程同时修改同一变量,会产生线程安全问题(竞争同一资源,互相覆盖、干扰),但注意单个线程修改一个变量是不会产生线程安全问题的;3.单个线程修改操作不是原子的【例如:i++(读取i值,计算i值,更新i值)不是原子操作】,在多线程的情况下修改中可以被别的线程打断,造成线程安全问题;4. 内存可见性问题【一个线程修改了共享变量,但由于cpu缓存,另一线程并没有读取到更新后的值就是内存可见性问题】,会引起线程不安全问题;5.指令重排序问题【cpu或编译器为了跑得更快,对机器的指令的执行顺序重新进行排列优化,但多线程环境下,这种优化,会破坏线程间的执行次序与可见性(互相看不到对方指令被重排序了,会读到半初始化、顺序错乱的值),导致程序出现不符合预期的并发问题就是指令重排序问题】,会引起线程不安全问题。

二.线程安全问题的解决方案

1.线程安全问题的根本原因是我们无法左右的,我们能解决的只有他后面的原因。解决原因二可以通过调整代码结构(将变量变为局部变量或使用ThreadLocal为多个线程自动创建各自的变量或使用不可变对象)、使用锁、使用原子类。解决原因三主要方法是通过加锁,将非原子的操作打包成原子操作,一旦加锁使其它线程无法再加锁只能阻塞等待解锁(注意线程之间要产生互斥效果需要有同一个锁对象【锁对象一般用currentThread()获取,synchronized修饰static修饰的方法,相当于针对当前类对象进行加锁】)。解决原因四主要方法使用volatile关键字修饰变量,告诉编译器不要去优化,即对变量读取时不会被优化成读取寄存器【不在内存里读取,把变量优化到寄存器】,保证了每次都可以读到最新值,还有一种方法是加锁。解决原因五方法依旧是使用锁与volatile修饰变量【对这个变量的读写操作加屏障,禁止前面与后面的代码互相跨过去重排序】。加锁不可以解决根本原因但其它的原因【原子性、可见性、指令重排序】都可以解决。

本节复盘到此结束,🦀🦀(若有误,望告知,感谢大家!

相关推荐
linux运维客栈1 小时前
Jenkins 最稳部署指南(含版本选择、Compose 部署、插件推荐)
java·servlet·jenkins
珹洺1 小时前
Java-servlet(五)手把手教你利用Servlet配置HTML请求与相应
java·运维·服务器·前端·servlet·html·maven
带刺的坐椅1 小时前
Java 版 Claude Code CLI 来了!(国产开源)Solon Code CLI 发布
java·ai·agent·solon·claudecode·soloncode
FYKJ_20102 小时前
springboot大学校园论坛管理系统--附源码42669
java·javascript·spring boot·python·spark·django·php
Open Source Thoughts2 小时前
OpenClaw.ai:Agentic AI 时代的“SpringFramework”时刻
java·人工智能·spring·prompt·开源软件·agi·ai-native
forestsea2 小时前
优雅终结启动顺序噩梦:ObjectProvider —— Spring 4.3 开始引入
java·后端·spring
小楼v2 小时前
⭐解锁RAG与Spring AI的实战应用(万字详细教学与完整步骤流程实践)
java·后端·rag·spring ai·ai大模型应用
希忘auto2 小时前
Spring IoC和DI
java
想不明白的过度思考者2 小时前
JavaEE进阶 ——【SpringBoot 快速上手】从环境搭建到HelloWorld实战
java·spring boot·spring·java-ee