volatile 关键字详解(中)

简介: 本文主要是讲解 volatile 关键字的使用,首概括它的三大特征,然后引入 JMM 模型,结尾我们解释了单例模式(懒汉模式)中为什么要用 volatile。

2、原子性


原子性指的是什么意思?


不可分割的,完整的,也即某个线程则横在做某个具体业务时,中间不可以被加塞或者分割。需要整体成功,或者同时失败。


MyData myData = new MyData();
for (int i = 0; i < 20; i++) {
    new Thread(() -> {
        for (int j = 0; j < 1000; j++) {
            myData.addPlusPlus(); // 方法内执行 this.number++;
        }
    }, "T" + i).start();
}
while (Thread.activeCount() > 2) {
    Thread.yield();
}
System.out.println(myData.number);


this.number++;是非线程安全的的操作所以结果不一定是 20000, 如果要保证原子性可以增加 synchronized关键字进行同步操作。或者使用 JUC 提供的 AtomicInteger线程安全类。


为什么数值少于 20000 ,我们通过 javap -c命令来看看


为了方便查看字节码。我修改了一下 ++ 程序


public class OnePlus {
    volatile int number = 0;
    public void addPlusPlus() {
        this.number++;
    }
}


字节码指令分析和查看


image.png


如何解决原子性问题?不用 sync


public class OnePlus {
    AtomicInteger number = new AtomicInteger(0);
    public void addPlusPlus() {
        number.getAndIncrement();
    }
}


3、有序性和指令重排序


在计算机执行程序时,为了提高性能,编译器和处理器的常常会对指令做重排, 一般分为三种情况。


源代码 ==> 编译器优化的重排 ==>指令并行的重排 ==> 内存系统的重排 ==> 最终执行的指令。


但线程的环境里面取保程序最终执行结果和代码顺序执行的结果一致。


处理器在进行重排序时必须要考虑之前的数据依赖性


多线程环境中线程交替执行,由于编译器优化重排的存在,两个线程中使用的变量能否保证一致性是否无法确定的,结果无法预测。


重排序1


public class MySort {
    int x = 11;  //语句 1
    int y = 12;  //语句 2
    x = x + 5;   //语句 3
    y = x * x;   //语句 4
}


可能的执行顺序:


1234

2134

1324


问题:请问第4可以重新排序后称为第一条吗?不能因为数据依赖性


重排序2


int a, b, y = 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


指令重排3


public class MyReSortSeqDemo {
    int a = 0;
    boolean flag = false;
    public void method1() {
        a = 1;          //语句1
        flag = true;    //语句2
    }
    public void method2() {
        if (flag) {
            a = a + 5;   //语句3
            System.out.println("*** retValue " + a);
        }
    }
}


相关文章
|
7月前
|
缓存 编译器
volatile关键字
volatile关键字
|
7月前
|
缓存 编译器 C语言
一起来探讨volatile关键字
在C语言中,volatile是一个关键字,用于告诉编译器不要对被声明为volatile的变量做优化,以确保每次对该变量的读写都直接操作内存。
|
缓存 安全 Java
【volatile关键字】
【volatile关键字】
|
4月前
|
存储 Java 编译器
|
4月前
|
缓存 Java 编译器
关键字: volatile详解
综上所述,`volatile`关键字是Java中实现轻量级同步的一个重要手段,主要用于确保变量的跨线程可见性,但并不保证操作的原子性。在多线程编程的过程中,合理地选择和使用 `volatile`关键字,对于提高程序的正确性和性能都至关重要。
47 0
|
存储 Java
浅谈Volatile关键字
该篇文章用来总结笔者对于Volatile关键字的理解,并不会太过深入的探讨。
140 0
浅谈Volatile关键字
|
SQL 缓存 Java
Volatile关键字介绍
Volatile关键字介绍
Volatile关键字介绍
|
存储 缓存 Java
volatile关键字再理解
volatile关键字再理解
volatile关键字再理解
|
编译器 程序员 C语言
C语言关键字详解(五)带你全面了解 volatile 关键字
C语言关键字详解(五)带你全面了解 volatile 关键字
381 0
C语言关键字详解(五)带你全面了解 volatile 关键字
|
缓存 安全 算法
你应该知道的 volatile 关键字(上)
不管是在面试还是实际开发中 volatile 都是一个应该掌握的技能。 首先来看看为什么会出现这个关键字。

热门文章

最新文章