线程安全(上)--彻底搞懂volatile关键字 (3)

由于Java中的运算并非是原子操作,所以导致volatile声明的变量无法保证线程安全。
对于这句话,我给大家举个例子。代码如下:

public class Test{ public static volatile int t = 0; public static void main(String[] args){ Thread[] threads = new Thread[10]; for(int i = 0; i < 10; i++){ //每个线程对t进行1000次加1的操作 threads[i] new Thread(new Runnable(){ @Override public void run(){ for(int j = 0; j < 1000; j++){ t = t + 1; } } }); threads[i].start(); } //等待所有累加线程都结束 while(Thread.activeCount() > 1){ Thread.yield(); } //打印t的值 System.out.println(t); } }

最终的打印结果会是1000 * 10 = 10000吗?答案是否定的。
问题就出现在t = t + 1这句代码中。我们来分析一下
例如:
线程1读取了t的值,假如t = 0。之后线程2读取了t的值,此时t = 0。
然后线程1执行了加1的操作,此时t = 1。但是这个时候,处理器还没有把t = 1的值写回主存中。这个时候处理器跑去执行线程2,注意,刚才线程2已经读取了t的值,所以这个时候并不会再去读取t的值了,所以此时t的值还是0,然后线程2执行了对t的加1操作,此时t =1 。
这个时候,就出现了线程安全问题了,两个线程都对t执行了加1操作,但t的值却是1。所以说,volatile关键字并不一定能够保证变量的安全性。

什么情况下volatile能够保证线程安全

刚才虽然说,volatile关键字不一定能够保证线程安全的问题,其实,在大多数情况下volatile还是可以保证变量的线程安全问题的。所以,在满足以下两个条件的情况下,volatile就能保证变量的线程安全问题:

运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值。

变量不需要与其他状态变量共同参与不变约束。

讲到这里,关于volatile关键字的就算讲完了。如果有哪里讲的不对的地方,非常欢迎你的指点。下篇应该会讲synchronize关键字。

参考书籍:

深入理解Java虚拟机(JVM高级特性与最佳实践)。

Java并非编程实战

如果你习惯在微信看文章,欢迎关注公众号:苦逼的码农,获取更多原创文章,后台回复”礼包”送你一份资源大礼包。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsfpgs.html