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

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

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

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

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

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

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

相关推荐
Gofarlic_oms11 小时前
利用API实现ANSYS许可证管理自动化集成
运维·服务器·开发语言·matlab·自动化·负载均衡
AI+程序员在路上2 小时前
VS Code 完全使用指南:下载、安装、核心功能与 内置AI 编程助手实战
开发语言·人工智能·windows·开源
invicinble2 小时前
这里对java的知识体系做一个全域的介绍
java·开发语言·python
catchadmin3 小时前
使用 PHP TrueAsync 改造 Laravel 协程异步化的可行路径
开发语言·php·laravel
wbs_scy3 小时前
【Linux 线程进阶】进程 vs 线程资源划分 + 线程控制全详解
java·开发语言
ss2733 小时前
食谱推荐系统功能测试如何写?
java·数据库·spring boot·功能测试
AI人工智能+电脑小能手3 小时前
【大白话说Java面试题】【Java基础篇】第15题:JDK1.7中HashMap扩容为什么会发生死循环?如何解决
java·开发语言·数据结构·后端·面试·哈希算法
m0_674294643 小时前
如何编写SQL存储过程性能对比_记录执行时间评估优化效果
jvm·数据库·python
try2find4 小时前
打印ascii码报错问题
java·linux·前端
014-code4 小时前
CompletableFuture 实战模板(超时、组合、异常链处理)
java·数据库