首页 > 其他分享 >为什么多线程下会有线程安全问题

为什么多线程下会有线程安全问题

时间:2023-07-23 18:11:06浏览次数:30  
标签:变量 修改 flag 线程 操作 下会 多线程

原子性:加锁(乐观锁CAS、悲观锁)

原子性是指一个操作或一系列操作要么全部执行成功并且不被中断,要么完全不执行,没有中间状态。在多线程或并发环境下,如果一个操作是原子性的,那么其他线程不会在该操作执行过程中看到该操作的部分结果。原子性是为了保证操作的一致性和正确性。例如,一个转账操作,涉及从一个账户扣除一定金额并将其添加到另一个账户,这个操作应该是原子的,否则可能导致数据不一致的情况。

可见性:voliate、加锁(乐观锁CAS、悲观锁)

可见性是指当一个线程对共享变量进行了修改后,其他线程能够立即看到这个修改。在多线程环境中,每个线程都有自己的缓存,如果一个线程修改了共享变量,其他线程可能并不立即知道这个变化,而是需要一定的机制来保证修改对其他线程可见。可见性问题可能导致线程之间的数据不一致性和错误行为。解决可见性问题的常见方法是使用同步机制,如锁或volatile变量,来确保变量的修改对其他线程是可见的。

线程出现线程安全问题的原因(主要原因)

① 线程在系统调度中顺序无序,抢占式执行,谁先抢到谁执行.

② 多线程修改同一个变量

③ 修改操作不是原子(不可分割的最小单位)的,如++操作就涉及到CPU的三个指令:

load 加载,add 增加,save 保存.如果两个线程对同一个变量进行操作时,会有很多排列顺序,就会造成变量值计算的最终结果不是预期结果.

④ 内存可见性:在多线程环境下,编译器对于代码的优化,产生误判(某个变量明明在其它线程执行过程中更改了,但是当前线程不知道),所以会引起bug.比如假设线程A的中断条件为某个变量flag=1才可以中断(默认flag = 0 不满足线程A中断条件),线程B在执行过程中将flag=1(满足线程A中断条件),但是线程A没有休眠,执行速度极快,编译器就会对代码进行优化(只加载一次flag的值),当线程B将flag=1时,线程A并不会重新加载flag的值,所以就会造成线程A无法中断,从而bug出现.

⑤ 指令重排序:完成某个任务的结果一样,但是过程顺序不一致.在多线程情况下,可能会使结果不可预知,从而产生bug.(很难调试出来,完全靠自己去想去理解)这里给大家举个例子:

我们实例化某个对象时,new操作主要分为三步:

1) 创建出对象(建好房子)

2) 构造对象(装修房子)

3) 将生成的地址赋值给对象引用(拿到钥匙).

多线程情况下,线程调度无序,那么某个线程可能会拿到一个没有构造好的对象(啥也没有,属性都是默认的),那么我们去使用该对象成员变量或方法时,可能就会发生一系列的错误.

标签:变量,修改,flag,线程,操作,下会,多线程
From: https://www.cnblogs.com/yifanSJ/p/17575359.html

相关文章

  • 基于C++11特性的线程池
    写在前面:本文学习自基于C++11实现线程池,代码部分均属于该博主,自己只是想记录以下自己的认知,并以这种方式加深一下自己对于多线程的理解1前置知识左值和右值左值(Lvalue):左值是指具有持久性和地址的表达式。简单来说,左值是可以被引用的、可以取地址的表达式。左值可以是变量、对......
  • 设备驱动-10.中断子系统-4.2中断线程化处理-workqueue
    1工作队列workqueue引入定时器、tasklet,它们都是在中断上下文中执行,它们无法休眠。那么如果一旦中断要处理耗时复杂的操作,就会显得很卡。那么使用内核线程来处理这些耗时的工作,那就可以解决系统卡顿的问题。Linux内核中工作队列workqueue就是线程化处理的一种方式,“工作队列”(......
  • Java多线程详解——一篇文章搞懂Java多线程
    Java多线程详解——一篇文章搞懂Java多线程目录1.基本概念2.线程的创建和启动2.1.多线程实现的原理2.2.多线程的创建,方式一:继承于Thread类2.3.多线程的创建,方式一:创建Thread匿名子类(也属于方法一)2.4.多线程的创建,方式二:实现Runnable接口2.4.1.比较创建线程的两种......
  • JavaScript多线程
    JavaScript多线程实现流程1.基本概念在开始讲解JavaScript多线程之前,我们需要先了解一些基本概念。单线程:JavaScript是一门单线程语言,即每次只能执行一项任务。这是因为JavaScript的设计初衷是用于前端交互和操作DOM,多线程会带来复杂性和安全性问题。多线程:多线程指的是同时......
  • android 线程更新ui
    Android线程更新UI的实现简介在Android开发中,我们常常会遇到需要在后台线程中进行耗时操作,然后在UI线程中更新界面的情况。本文将介绍如何实现在Android中使用线程更新UI,并提供相应的代码示例和解释。实现流程下面是实现"Android线程更新UI"的整个流程:步骤描述步骤1......
  • java多线程
    java中多线程的实现其实和c++类似,介绍几种常用方法1.继承Thread类,重写其run方法classMyThreadextendsThread{publicMyThread(){}publicMyThread(Stringname){super(name);}@Overridepublicvoidrun(){System.out.p......
  • Linux 网络基础 2 三次握手 三次挥手 多进程 多线程服务器
    1.包裹函数对服务器客户端等函数进行报错处理以及简化处理比如bindinttcp4bind(shortport,constchar*IP){structsockaddr_inserv_addr;intlfd=Socket(AF_INET,SOCK_STREAM,0);bzero(&serv_addr,sizeof(serv_addr));if(IP==NULL){//......
  • 在docker内定位占用cpu过高的java线程
    参考​​>确定进程信息判断该进程是否在Docker容器中。使用cat/proc/<pid>/cgroup查看打印内容是否包含:/docker/。原理是Docker使用了Linuxcgroups使用pstree-s<pid>查看打印的进程树是否包含docker-containe,显示信息如下:systemd(1)───docker(1101)───docke......
  • Spring Boot中内置Tomcat最大连接数、线程数与等待数 实践调优
    在SpringBoot框架中,我们使用最多的是Tomcat,这是SpringBoot默认的容器技术,而且是内嵌式的Tomcat。Tomcat是Apache基金下的一个轻量级的Servlet容器,支持Servlet和JSP。Tomcat服务器本身具有Web服务器的功能,可以作为独立的Web服务器来使用。一、SpringBoot应用......
  • Linux中内核线程可以被抢占吗?
    1背景 说起抢占,需要关注服务器上Linux内核中的CONFIG_PREEMPT_xxx采用的何种模式,下面是几个比较常见系统的配置方式例如REHL以及centos7使用的是CONFIG_PREEMPT_VOLUNTARY又例如SLES以及龙蜥OS使用的是CONFIG_PREEMPT_NONE 咱们这里要分析的就是在CONFIG_PREEMPT_VOLUN......