volatile使用场景
volatile的可以在以下场景中使用:
当运算结果不依赖变量当前的值,或者能确保只有单一线程修改变量的值的时候,我们才可以对该变量使用volatile关键字
变量不需要与其他状态变量共同参与不变约束
volatile与原子性
volatile关键字能保证变量的可见性和代码的有序性,但是不能保证变量的原子性,下面我再举一个volatile与原子性的例子:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | public class VolatileTest { public static volatile int count = 0; public static void increase() { count++; } public static void main(String[] args) { Thread[] threads = new Thread[20]; for(int i = 0; i < threads.length; i++) { threads[i] = new Thread(() -> { for(int j = 0; j < 1000; j++) { increase(); } }); threads[i].start(); } //等待所有累加线程结束 while (Thread.activeCount() > 1) { Thread.yield(); } System.out.println(count); } } |
上面这段代码创建了20个线程,每个线程对变量count进行1000次自增操作,如果这段代码并发正常的话,结果应该是20000,但实际运行过程中经常会出现小于20000的结果,因为count++这个自增操作不是原子操作。
上面的count++自增操作等价于count=count+1,所以JVM需要先读取count的值,然后在count的基础上给它加1,然后再将新的值重新赋值给count变量,所以这个自增总共需要三步。

上图中我将线程对count的自增操作画了个简单的流程,一个线程要对count进行自增时要先读取count的值,然后在当前count值的基础上进行count+1操作,最后将count的新值重新写回到count。
如果线程2在线程1读取count旧值写回count新值期间读取count的值,显然这个时候线程2读取的是count还未更新的旧值,这时两个线程是对同一个值进行了+1操作,这样这两个线程就没有对count实现累加效果,相反这些操作却又没有违反volatile的定义,所以这种情况下使用volatile依然会存在多线程并发安全的问题。
尚学堂给同学们带来全新的Java300集课程啦!java零基础小白自学Java必备优质教程_手把手图解学习Java,让学习成为一种享受_哔哩哔哩_bilibili尚学堂给同学们带来全新的Java300集课程啦本课程为Java300集2022版第一季,配合最新版的Java课程,所有视频重新录制,课件所有图形做了重新绘制和配色,图解学习Java,让学习成为一种享受本套教程专门为零基础学员而制,适合准备入行Java开发的零基础学员,视频中穿插多个实战项目。每一个知识点都讲解的通俗易懂,由浅入深。不仅适用于零基础的初学者,有经验的程序员也可做巩固学习。后续课
https://www.bilibili.com/video/BV1qL411u7eE?spm_id_from=333.999.0.0