有volatile在,变量一定会安全吗?

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/YSC1123/article/details/77890759

        在编程中,安全问题一直是我们关注的重点,能否确保程序在多线程的情况下实现安全,这应该一直是各位攻城狮们极其在意的。今天小编就和大家一起接着上篇博客继续聊一聊 关于原子性和可见性的问题!

✎  什么是原子性

      大家都知道,原子是构成物质的最小单位,所以可以将原子性理解成为不可分性,比如数据库中的第一范式,强调的列的原子性,即列不能再进行分割。而原子性在多线程的环境下,可以理解为某一个变量不能同时被多个线程同时操作;

     举个栗子:A、B两个学生同时去应聘同一个职位,而这个职位只能其中一个人就职,也就是说:要么A干,要么B干。所以这个职位就是具有原子性的。

     在Java中,具有原子性的主要有<return a; > 、<a = 2; > 等;那么a++ 或者++a这种操作具有原子性吗?答案是:不具有!因为对于a++这种操作,共需要经历三步:获取a的值--> 执行++ -->将结果赋值给a; 而在这个过程中,并不能保证是单线程操作,或者正是因为无法保证在多线程中的安全性,所以有了automic的原子类来帮助完成a++的安全操作;

     因此,原子性是指不论处理器是单核还是多核,也不管是单线程还是多线程,在同一个时刻只能有一个线程执行操作;

✎ 可见性又是对谁可见

     提起volatile,直接想到的就是volatile是将变量的值维护在内存中,可以确保每个线程的操作访问到的值都是来自内存,可以保证多个线程读取到的是同一份数据。问题来了:

1、为什么就可以维护在内存中一份数据?

2、读取的同一份数据就安全吗?

    解读一:

         之所以可以保证多个线程都读取同一份来自内存的数据,主要跟volatile有关,在线程对变量操作之后,会有store屏障强制将变量的值更新为当前的值;而在某线程来获取该变量值时,volatile又可以使用load屏障指令强制当前线程更新该变量值为当前内存中维护的这个值。这样一来,每次被操作之后,变量的值都会被强制一下,这样无论变量的值更新为多少,每个线程都会拿到这个变量的最新值。

   解读二:

        虽然做到了变量的值是最新的,但是在多线程环境下并不能保证当前变量一定是线程安全的,如果当前有两个线程同时对变量a = 1进行获取和更新操作,然后线程A首先对变量a进行了+1 的操作,而在将+1的结果赋值给a的时候,线程B已经先A线程一步将a的值更新为3,这时候就会出现一个问题:本来线程A只是为了将a变量赋值成2;

        结果由于线程B的提前介入,a的值已经不是线程A期望的结果了,这就是简单的非线程安全的场景。

✎ 如何解决volatile的线程安全问题

      解决线程安全问题,不要忘了开篇时候说道的原子性,多线程会有问题,我们是否可以让它实现原子性的操作??当然可以,就是我们的synchronize关键字,在多个线程对同一个变量进行访问时,做一下控制,只让一个线程来操作,这样就不会出现线程安全问题;最典型的操作:

     单例模式中的双重校验!

    到这里就基本结束了,不知道小编的这些见解有没有帮你解答心中的疑惑呢?

 

    

    

       

展开阅读全文

C++中的全局变量,您一定会吗?

09-03

若一个工程由两个文件组成,分别为file1,file2。在文件1中定义了全局变量n,在文件2中只要由这个变量的申明就可以使用,这个大家都知道,原因就是因为全局变量放到了程序的数据区,而数据区是属于整个程序中的所有的文件的,所以所有的文件都能“看得见”其他文件所定义的全局变量。但看看这段代码,再想一个问题。rn//*******File1*******rn#include rnrnint n;rnrnvoid Fun1InFile1(void)rnrn n=100;rn cout << "n=" << n << endl;rnrnrn//******File2*******rn#include rnvoid Fun1InFile1(void);rnextern int n;rnvoid main()rnrn Fun1InFile1();rn cout <<"n=" << n << endl; //statement 1rnrn 这个结果一个是100,而另一个是0(实质上应该是随机数)。实质上这里和多文件没有关系,即便Fun1InFile1()和main()再一个文件中,也是同样的结果。rn 但不知道大家想过没有这样一个问题:既然全局变量n再数据区存放,那么Fun1InFile1()和main()对n操作时是对同一个内存块操作,它们的数值应该是由连续性的,即statemnet 1也应该输出100才对呀!rn 是否可以这样理解,函数对全局变量的操作时候,实质上是对全局变量的一个临时拷贝操作,而没有对全局数据区的那个变量的内存块操作。若真是这样,就出现一个问题!临时拷贝都是常量,没有变量,而常量是不可能再赋值的那么“n=100”就不应该编译通过!rn 论坛

没有更多推荐了,返回首页