参考
介绍
volatile 关键字保证变量的内存可见性,禁止指令重排序, 不保证原子性。
内存可见性
内存可见性是指当一个线程修改了某个变量的值,其它线程总是能知道这个变量变化。也就是说,如果线程 A 修改了共享变量 V 的值,那么线程 B 在使用 V 的值时,能立即读到 V 的最新值。
禁止指令重排序
为了提高性能,在遵守 as-if-serial 语义(即不管怎么重排序,单线程下程序的执行结果不能被改变。编译器,runtime 和处理器都必须遵守。)的情况下,编译器和处理器常常会对指令做重排序。使用 volatile 修饰变量时,根据 volatile 重排序规则表,Java 编译器在生成字节码时,会在指令序列中插入内存屏障指令来禁止特定类型的处理器重排序。内存屏障是一组处理器指令,它的作用是禁止指令重排序和解决内存可见性的问题。
代码
不安全的测试
package future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Author 夏秋初
* @Date 2022/3/4 16:01
*/
public class Test1 {
public static int num;
public static void main(String[] args){
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int j = 0; j < 10; j++) {
num++;
}
}, String.valueOf(i)).start();
}
/**
* 等待只剩 main 与 gc 线程才进行下一步
*/
while (Thread.activeCount() > 2) {
}
System.out.println(num);
}
}
线程安全的测试
不使用锁及synchronized
package future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* @Author 夏秋初
* @Date 2022/3/4 14:19
*/
public class Test {
/**
* volatile 只是保证可见性,并不能保证原子性
* AtomicInteger 是 juc 提供的无锁工具包 Integer 工具类,通过调用 jni 本地接口方法实现。
*/
public static volatile AtomicInteger num = new AtomicInteger();
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10; i++) {
new Thread(()->{
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int j = 0; j < 10; j++) {
num.getAndIncrement();
}
}, String.valueOf(i)).start();
}
/**
* 等待只剩 main 与 gc 线程才进行下一步
*/
while (Thread.activeCount() > 2){
}
System.out.println(num);
}
}
可见性测试
System.out.println("当前 A status 的值为"+ status); 可以获取最新的 A status,但是 A 线程的 while 获取不到最新的值并且还在运行
package future;
import java.util.concurrent.TimeUnit;
/**
* @Author 夏秋初
* @Date 2022/3/4 16:03
*/
public class Test2 {
/**
* 可见性测试
*/
public static Boolean status = true;
public static volatile Boolean vstatus = true;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
while (status){
}
System.out.println("A执行完毕");
},"A").start();
new Thread(()->{
while (vstatus){
}
System.out.println("B执行完毕");
System.out.println("当前 A status 的值为"+ status);
},"B").start();
TimeUnit.SECONDS.sleep(3);
status = false;
vstatus = false;
}
}