volatile 修饰布尔的标记位
volatile 适用于 boolean flag 如果一个共享变量, 一直只被各个线程赋值, 而没有其他的操作, 那么就可以用volatile来代替synchronized 或者代替原子变量, 因为对布尔变量的赋值自身是有原子性的, 而volatile保证了可见性, 就满足了线程安全. 因为布尔值, 只是改成true或者false, 具有原子性, 而不是像 a++操作是非原子性的.
volatile 修饰布尔适用的场景
如下的代码演示了 volatile 适用的场景. 关键是如下的方法setDone,只是直接把done 改成了true, 而没有像a++操作那样, 需要读取a之前的值 . 只是修改布尔值是原子性的. 因此适用.
package com.thread.jmm;import java.util.concurrent.atomic.AtomicInteger;/** * 类名称:UseVolatileInBoolean * 类描述:volatile 适用于 Boolean变量的并发修改 赋值 * * @author: https://javaweixin6.blog.csdn.net/ * 创建时间:2020/9/6 10:41 * Version 1.0 */public class UseVolatileInBoolean implements Runnable { volatile boolean done = false; //原子类, 统计执行了多少次 AtomicInteger atomicInteger = new AtomicInteger(); public static void main(String[] args) throws InterruptedException { UseVolatileInBoolean runnable = new UseVolatileInBoolean(); Thread thread1 = new Thread(runnable); Thread thread2 = new Thread(runnable); thread1.start(); thread2.start(); //主线程等待子线程执行完毕 thread1.join(); thread2.join(); System.out.println(runnable.done); System.out.println("运行次数 : "+runnable.atomicInteger.get()); } @Override public void run() { for (int i = 0; i
如下图所示的运行结果是为true
volatile 修饰布尔的标记位不适用的场景
如下的代码演示了volatile 修饰布尔的标记位不适用的场景 . 主要是flipDone方法中, 执行的是done = !done 是要先读取done的值, 再修改, 那么此时就不再是原子性的操作, 就可能会出现并发安全性问题.
package com.thread.jmm;import java.util.concurrent.atomic.AtomicInteger;/** * 类名称:UseVolatileInBoolean * 类描述:volatile 不适用的情况 Boolean * * @author: https://javaweixin6.blog.csdn.net/ * 创建时间:2020/9/6 10:41 * Version 1.0 */public class IncorrentVolatileInBoolean implements Runnable { volatile boolean done = false; //原子类, 统计执行了多少次 AtomicInteger atomicInteger = new AtomicInteger(); public static void main(String[] args) throws InterruptedException { IncorrentVolatileInBoolean runnable = new IncorrentVolatileInBoolean(); Thread thread1 = new Thread(runnable); Thread thread2 = new Thread(runnable); thread1.start(); thread2.start(); //主线程等待子线程执行完毕 thread1.join(); thread2.join(); System.out.println(runnable.done); System.out.println("运行次数 : "+runnable.atomicInteger.get()); } @Override public void run() { for (int i = 0; i
多次运行 , 可以看到 , 有时是返回true, 有时是返回的false
总结: 无论这个变量是什么类型, 只要这个变量只是被赋值的, 而没有其他的操作, 例如对比, 或者取值等, 那么此时对于volatile是适用的. 原因有两点:
赋值是原子性的, volatile又保证了可见性.