一次性搞清线程安全问题精华篇 -- 转载

i++为什么不是线程安全的吗?

i++不是原子操作,也就是说,它不是单独一条指令,而是3条指令(3条汇编指令):
1. 从内存中把i的值取出来放到CPU的寄存器中
2. CPU寄存器的值+1
3. 把CPU寄存器的值写回内存

由于线程不共享栈区,共享堆区和全局区,所以当且仅当 i 位于栈上是安全的,反之不安全(++i 也同理). 因为如果是全局变量的话,同一进程中的不同线程都有可能访问到。对于读值,+1,写值这三步操作,在这三步任何之间都可能会有 CPU 调度产生,造成 i 的值被修改,造成脏读脏写。

其实,最核心的就是这个 +1 的过程不是原子的,任何一个线程都可以打断这个过程,一旦打断,其他线程看到的值可能是落后的了;那么,对于 value-- 或者 --value 也就是一个道理了。-1 的过程不是原子的,多线程的调度不可预知,那么,线程在操作的过程中看到的值不是最新的,所以,就会存在一直减到负值的情况了。

来源:慕课网课程后问题解答

关于线程安全的问题,你在写代码时,哪些场景下才需要注意呢?

(1)对于 java 代码,如果你显示的使用了多线程(比如线程池或者是自己 new Thread),且你操作了全局变量(包括全局静态变量),那么,你一定要考虑线程安全的问题;
(2)对于 Spring 代码,由于我们的 Bean 没有额外定义的话,默认都是单例的,这在绝大多数情况下不会有问题,因为 Bean 基本上都是 “无状态的”(也就是 Bean 中不存在全局变量的情况),那么,此时,你没有任何必要去考虑线程安全的问题;反过来,如果你定义了有状态的 Bean,你就需要考虑了(但是,话又说回来,为什么要在 Bean 中定义全局变量呢?)
(3)即使你在使用多线程,但是,你操作的仅仅是局部变量(定义在方法中的变量),那么,你完全不需要考虑线程安全的问题,因为这些数据保存在线程自己的栈空,是绝对安全且不共享的
总结:如果你的数据被多线程共享,且存在修改的风险,需要注意线程安全;否则,没有必要在意!

来源:慕课网课程后问题解答

关于全局变量/局部变量/静态变量的线程安全问题

局部变量不存在线程安全问题。

静态变量在该类的所有实例之间共享,如果会进行修改的话会有线程安全问题。

全局变量在单例时会有线程安全问题,多例时不存在。
转载链接:https://blog.csdn.net/qq_38572383/article/details/86074521

全局变量的线程安全性

类的全局变量包含三种:值不会变的常量;单例模式的变量;多例模式的变量

常量和多例模式的变量永远是线程安全的

单例模式的变量就需要仔细考虑一下了:

如果单例模式的变量只是一个service,用它只是调用它的方法,不管方法是否有参数, 都是线程安全的

如果单例模式的变量虽是一个service,但调用者会给该service的一些属性赋值,并且这些值会在方法调用的时候发生作用,那么这个service就不是线程安全的

转载链接: https://blog.csdn.net/heidyxlw/article/details/71195546

静态变量和全局变量都可能引起线程安全问题。这两种变量引起线程安全问题的原因和区别

1、静态变量

静态变量即静态成员变量。只要有修改变量值的操作,无论是在单例或者非单例都是线程不安全的;而如果线程只是读取变量的值,而不会改变变量的值,这种情况下则是线程是安全的。

产生线程安全问题的原因:静态变量即类变量,只初始化一次,位于方法区,为所有对象共享,共享一份内存,一旦静态变量被修改,其他对象均对修改可见,故线程非安全。

静态变量多线程操作示例:
在这里插入图片描述
根据上图代码可知,当线程1执行了number = 1; number = 2; 后,线程2获得执行权,number = 1;然后当线程1获得执行权执行打印第二次获取number时; 必然输出结果“获取第二次number = 1”,按照这个模拟,我们可能会在控制台看到输出为“获取第二次number = 1”的结果。如下图方框中的数据:
在这里插入图片描述
上图结果显示了静态变量线程不安全问题。
2、全局变量

全局变量即实例成员变量。如果线程只是读取变量的值,而不会改变变量的值,则无论是单例还是非单例都是线程安全的;如果有修改变量值的操作,则单例模式因为只有一个对象实例singleton存在,多线程同时操作时是不安全的,而非单例模式下多线程操作是安全的。

实例变量为对象实例私有,在虚拟机的堆heap中分配,若在系统中只存在一个此对象的实例,在多线程环境下,“犹如”静态变量那样,被某个线程修改后,其他线程对修改均可见,故线程非安全(如,springmvc controller是单例的,非线程安全的);如果每个线程执行都是在不同的对象中,那对象与对象之间的实例变量的修改将互不影响,故线程安全(如,struts2 action默认是非单例的,每次请求在heap中new新的action实例,故struts2 action可以用实例成员变量)。

全局变量多线程操作示例:
在这里插入图片描述多线程操作同一个对象的全局变量,结果如下图:
在这里插入图片描述
上图结果显示了全局变量线程不安全问题。

转载连接:http://www.hzdledu.cn/hzzx/jswz/846.html

全局变量对线程安全的影响成因

线程安全问题都是由全局变量及静态变量引起的。但是,如果每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;如果有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

常量始终是线程安全的,因为只存在读操作。
每次调用方法前都新建一个实例是线程安全的,因为不会访问共享的资源。
局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部变量,它不是共享的资源。局部变量包括方法的参数变量和方法内变量。

转载 https://www.cnblogs.com/sjzxxy/p/12980538.html

线程安全问题都是由全局变量及静态变量引起的

1.线程安全问题都是由全局变量及静态变量引起的。但是,如果每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;如果有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。

2.1) 常量始终是线程安全的,因为只存在读操作。

2)每次调用方法前都新建一个实例是线程安全的,因为不会访问共享的资源。

3)局部变量是线程安全的。因为每执行一个方法,都会在独立的空间创建局部变量,它不是共享的资源。局部变量包括方法的参数变量和方法内变量。
在这里插入图片描述

转载链接:https://blog.csdn.net/m0_37771869/article/details/81258188

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值