当前位置:首页 > Java技术 > java多线程会造成线程安全问题的原因总结

java多线程会造成线程安全问题的原因总结

2022年09月17日 08:43:18Java技术6

众所周知,多线程会造成线程安全问题,那么多线程为什么会导致线程安全问题呢?

一:首先了解jvm内存的运行时数据区

        1.堆区:存储对象实例(和实例变量),数组等

        2.java虚拟机栈(方法·栈),存放方法声明,局部变量,对象的引用变量,基本数据类型变量等

        3.本地方法栈:存储一些本地方法(native关键字修饰的方法,如hashCode()方法,clone方法,Thread类的star0()方法)

        4.方法区:存储类元数据,常量,静态变量等

        5.程序计数器:记录程序执行的位置,保证cpu切换上下文时,可以从上一次执行的位置开始执行

 二:内存空间的共享情况

        堆区与方法区都是线程共享的,而栈区如方法栈则是线程私有的

三:一个线程的大致组成结构

        1.每一个线程都有自己的线程栈,因此线程与线程之间是相互独立的

        2.一个线程栈里面有自己的程序计数器,方法栈

        3.方法栈里面又是通过栈帧的形式存储局部变量表,操作数栈,方法出口

        4.方法中的局部变量则是存储在局部变量表中,数据操作则是在操作数栈中进行

四:多线程引起线程安全原因(实质是造成了读写不一致)

        1.当多个线程操作共享空间中的变量时,就有可能造成线程安全问题(如一个线程更新变量之前,另一个线程读到了旧值并已经更新了,导致该线程再去更新时,更新的值相对来说就不正确了)

        2.结合内存空间的共享性,也就是说,当多个线程同时操作堆区中对象的成员变量,或者方法区中的静态变量时,就会造成线程安全问题

五:深入理解为什么线程之间会造成读写不一致

        首先线程并发导致安全问题的根本原因主要有3个

        1.原子性:线程切换会带来原子性问题,使用锁即可解决。java中只有简单的赋值操作,如i = 100是原子性操作,但是i = j则不是

        2.可见性:由于cpu高速缓存的存在,可能会导致线程对一个变量修改没有及时被其他线程所看见,使用volatile关键字即可解决

        3.有序性:jvm会对代码进行优化,从而会把代码进行重排序,使用volatile关键字可以禁止重排序

        注意:volatile只能保证可见性与有序性,不能保证原子性

       那么volatile是如何保证可见性与有序性的呢?

        首先说明为什么线程并发会导致可见性问题,以及可见性带来的影响

        java内存模型分为线程的工作内存(可以理解为线程栈)与主内存(可以理解为堆以及方法区)。主内存则会存放着一些共享变量;工作内存则是每一个线程独有的。当要操作主内存的变量时,线程会先从主内存中复制一份缓存到自己的工作内存,然后在自己的工作内存对值进行修改,之后再把值更新到主缓存中。因此当有一些线程事先缓存了变量或者线程修改的变量没有及时更新到主内存中,就会导致线程安全问题

        volatile则是可以保证线程修改变量后,马上更新到主内存,而且其他线程中即使缓存了该变量,也强制必须从主内存中获取值,从而解决了共享变量的可见性问题

        那为什么不能保证原子性呢?

        举个例子,比如 volatile i = 100,i++;首先一个线程读取到i = 100,然后阻塞了,另外一个线程进来,读取到 i = 100,再自增并且赋值,刷新主内存i = 101,此时其他线程对i的修改肯定是可见的,但是上一个阻塞的线程已经读到了 i = 100了,然后再++,依然是101,那么也就是说,volatile并没有保证原子性(i++有三个操作,读取,自增,赋值,java中只有简单的赋值才是原子性操作)  

五·:解决线程安全问题的思路(同时满足原子性,可见性与有序性)

        1.避免线程修改共享空间中变量的值

        2.使用无状态对象,即不共享状态(数据)给多个线程

        3.使用不可变对象,不可修改,就不会存在读写不一致的问题

        4.使用线程特有对象,如TheadLocal

        5.装饰者模式,即使用原子类,原子操作

        6.使用锁,保证线程同步,如Syconized,RetranceLock等

        

作者:_小白不黑
来源链接:https://blog.csdn.net/m0_57713282/article/details/120573047

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/42497.html

分享给朋友:

“java多线程会造成线程安全问题的原因总结” 的相关文章

Java虚拟机1:什么是Java

Java虚拟机1:什么是Java

前言 让我们来看一下Java的广告词,来自http://www.java.com/zh_CN/about/: 97%的企业桌面运行Java 美国有89%的桌面(或计算机)运行Java 全球有900万Java开发人员 开发人员的头号选择...

Java 日志框架详解

Java 日志框架详解

1. JUL学习 JUL全称Java util Logging是java原生的日志框架,使用时不需要另外引用第三方类库,相对其他日志框 架使用方便,学习简单,能够在小型应用中灵活使用。 1.1 架构介绍 Loggers...

java计数循环及小技巧

要运行一个很大次数的循环应该选择一个小数,然后去判断 例如本例子是100可以选择10去判断 public static void main(String[] args) { // TODO Auto-generated metho...

Java实现1到n的倒数的累加和

Java实现1到n的倒数的累加和

从键盘读入一个数,然后进行运算 实现代码: public static void main(String[] args) { Scanner in=new Scanner(System.in); int n ; n=in....

Java获取明天的时间(当前时间加一天)

import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar;     public class&nbs...

Java Web 工作技巧总结 16.8

Java Web 工作技巧总结 16.8

摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! 四时不谢之兰,百节长青之竹,万古不败之石,千秋不变之人。 1. AOP – LOG 项目中,一个请求过来,一个响应回去。...

Java 基础:hashCode方法

Java 基础:hashCode方法

Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket 一、前言     泥瓦匠最近被项目搞的天昏地暗。发现有些要给自己一些目标,关于技术的目标: 专注...

JAVA UUID 生成唯一标识

Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket Reprint it anywhere u want 需求     项目在设计表的时候,要处理并发多...

java总结文章

java总结文章

java总结文章 原创地址: http://www.cnblogs.com/Alandre/ (泥沙砖瓦浆木匠),需要转载的,保留下! Thanks Talk is cheap. Show me the...

java 实现图片压缩

转载https://www.cnblogs.com/strongmore/p/14158639.html 添加依赖 <dependency> <groupId>net.coobird</groupId> <artifa...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。