Volatile
1、保证可见性
package com.sw.volatileDemo;
import java.util.concurrent.TimeUnit;
/**
* @Author suaxi
* @Date 2021/2/19 22:07
*/
public class JMMTest {
//不加volatile程序会死循环
//加上volatile保证了可见性
private volatile static int num = 0;
public static void main(String[] args) { //main线程
new Thread(() ->{ //线程1
while (num == 0){
}
}).start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
num = 1;
System.out.println(num); //输出num=1,main线程将num改为1后,线程1还在循环while(num == 0)
}
}
2、不保证原子性
原子性:任务在执行的过程中不能被分割,也不能被干扰,一组操作要么都成功,要么都失败
不保证原子性测试实例:
package com.sw.volatileDemo;
/**
* @Author suaxi
* @Date 2021/2/19 22:25
* volatile不保证原子性
*/
public class VolatileTest01 {
private volatile static int num = 0;
public static void add() {
num++;
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
new Thread(() ->{
for (int j = 0; j < 1000; j++) {
//理论上默认相加的结果等于2000
add();
}
}).start();
}
while (Thread.activeCount() > 2){ //Java中main线程和gc线程默认运行
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+" "+num);
//19359
//18089
//不使用锁的实际相加的情况不等于2000
//volatile不保证原子性
}
}
如何在不使用synchronized和lock锁的情况下保证原子性?
图片来源:狂神说Java
答:使用原子类解决
package com.sw.volatileDemo;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Author suaxi
* @Date 2021/2/19 22:25
* volatile不保证原子性
* 使用Atomic原子类解决原子性问题
*/
public class VolatileTest02 {
private volatile static AtomicInteger num = new AtomicInteger();
public static void add() {
//num++;
num.getAndIncrement(); //AtomicInteger中的 +1 方法
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
new Thread(() ->{
for (int j = 0; j < 1000; j++) {
//理论上默认相加的结果等于2000
add();
}
}).start();
}
while (Thread.activeCount() > 2){ //Java中main线程和gc线程默认运行
Thread.yield();
}
System.out.println(Thread.currentThread().getName()+" "+num);
}
}
3、禁止指令重排
指令重排:源代码 ---> 编译器优化的重排 ---> 指令并行也可能会重排 ---> 执行
假设x y a b四个数的默认值为0
线程1 | 线程2 |
---|---|
x = a | y = b |
b = 1 | a = 2 |
正常的执行结果为:x=0,y=0
线程1 | 线程2 |
---|---|
b = 1 | a = 2 |
x = a | y = b |
指令重排可能导致的结果:x =2,y=1
Volatile可以避免指令重排:
内存屏障,作用:
1、保证操作的执行顺序
2、保证某些变量的内存可见性
评论 (0)