java多线程中volatile关键字到底有啥用啊( 二 )

这段代码的含义是,有5个线程,每一个线程都对a进行递增。每个线程一次加10个数。按道理来讲,如果volatile关键字保证原子性的话,最后结果一定是50。我们可以运行一下看看结果:

java多线程中volatile关键字到底有啥用啊


最后得出的结论就是volatile不保证原子性。既然不能保证原子性,那肯定就是非线程安全的。
2、单例模式的双重锁为什么要加volatile?什么是双重锁的单例模式,我们给出代码可以看看。
public class Test2 { private static volatile Test2 test2; public static Test2 getInstance() { if(test2 == null) { synchronized (Test2.class) { if(test2 == null) { test2 = new Test2(); } } } return test2; }}这就是单例模式的双重锁实现,为什么这里要加volatile关键字呢?我们把test2 = new Test2()这行代码进行拆分。可以分解为3个步骤:
【java多线程中volatile关键字到底有啥用啊】 (1)memory=allocate();// 分配内存(2)ctorInstanc(memory) //初始化对象(3)test2=memory //设置s指向刚分配的地址
如果没有volatile关键字,可能会发生指令重排序。在编译器运行时,从1-2-3 排序为1-3-2。此时两个线程同时进来的时候出现可见性问题,也就是说一个线程执行了1-3,另外一个线程一进来直接返回还未执行2的null对象。而我们的volatile关键之前已经说过了,可以很好地防止指令重排序。也就不会出现这个问题了。
如果我们学过java并发系列的其他类比如说Atomic等,通过源码我们会发现volatile无处不在。
万水千山总是情,点赞再走行不行!!!万水千山总是情,点赞再走行不行!!!万水千山总是情,点赞再走行不行!!!
■网友
volatile 一般用于boolean变量,有几个作用,我知道的有防止脏读,第2增加了内存屏障。

■网友
这个问题确实很难用代码来复现,完全就是跟主存回写抢时间啊。大概撸了一段code,确实可以看出volatile的功效。"悲剧《我被停止了" 不管过多久都不会打印,这个线程死在while了
public class TestArr {\tstatic boolean isKill = false;\tpublic static void main(String args) {\t\tnew Thread(){\t\t\tpublic void run() {\t\t\t\twhile(!isKill) {\t\t\t\t}\t\t\t\tSystem.out.println("悲剧《我被停止了");\t\t\t};\t\t}.start();\t\ttry {\t\t\tThread.sleep(1000);\t\t} catch (InterruptedException e) {\t\t\te.printStackTrace();\t\t}\t\tisKill = true;\t\tSystem.out.println("赶快停止吧 iskill = " + isKill);\t}}

■网友
不能保证并发安全,只能保证的是当前从内存中读出来的值是最新的
■网友
volatile不能避免并发问题,比如两个线程同时加一个volatile的static的数=0,各加一万次1,我们可能是想得到两万,但是volatile只是保证这个公共的数可见,这是如果出现一次两个线程同时读这个数,都加一得到相同的结果,那么最后的结果就有可能是19999,而不是20000,这个属性主要是在无锁的里面有用,单独的解决不了并发和并行带来的问题
■网友
一般volatile关键字用来处理原子操作的数据,能保证线程安全,非原子操作不能保证线程安全。


推荐阅读