首页 > 其他分享 >volatile

volatile

时间:2024-08-02 14:09:08浏览次数:6  
标签:缓存 变量 屏障 线程 volatile public

可见性问题复现

线程1不会停止,因为线程2改变了a的值,线程1不知道

public class Test {
    public static Integer a = 1;

    public static void main(String[] args) {

        // 线程1 根本停不下来
        new Thread(() -> {
            while (a == 1){
               
            }
        }).start();

		// 线程2 2秒后修改 a 的值
        new Thread(() -> {
            LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
            a = 2;
        }).start();
    }
}

但是如果这样写线程1就会停下来,没搞明白...(至少上面的代码证明了可见性的问题)

public class Test {
    public static Integer a = 1;

    public static void main(String[] args) {

        new Thread(() -> {
            while (a == 1){
                LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(500));
                System.out.println("此时变量还是1");
            }
        }).start();


        new Thread(() -> {
            LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
            a = 2;
        }).start();
    }
}

第一段代码中,如果变量使用 volatile 修饰,线程1 就会停下来

volatile

可以保证变量的可见性、有序性

可见性

可以理解为,每个线程不是读取自己的工作内存,而是直接读取主内存,每次修改都会回写主内存,更深入的原因是缓存一致性,官方描述如下(不是很理解,后面再看):

当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取

有序性

java 代码最终翻译成可执行的机器指令会被优化、或者只能保证赋值操作啥的是准确的,但是不一定就是我们写的代码的顺序,这就是 指令重排序,底层使用内存屏障来完成的,对于 volatile 完整的情况应该是这样的(不是很理解,后面再看)

  1. 在每一个volatile的写(store)之前,加入一个StoreStore屏障和一个LoadStore屏障
  2. 在每一个volatile的写(store)之后,加入一个StoreLoad屏障和一个StroeStore屏障
  3. 在每一个volatile的读(load)之后,加一个LoadLoad屏障和LoadStrore屏障

标签:缓存,变量,屏障,线程,volatile,public
From: https://www.cnblogs.com/cyrushuang/p/18338623

相关文章

  • JavaEE 初阶(8)——多线程6之线程安全下-->volatile
    之前,我们在 JavaEE初阶(6) 这篇文章中,谈到过引起线程不安全的原因,初步了解了 “可见性” “Java内存模型” “指令重排序”,本章讲解volatile会涉及到这三个知识点,详细内容可以参考  JavaEE初阶(6) 这篇文章。目录一. 引入二.volatile关键字 a.保证“可......
  • volatile 关键字的工作机制
    Author:ACatSmilingSince:2024-07-24volatile关键字:是Java编程语言中的一个重要工具,用于控制变量在多线程环境中的可见性和有序性。前置知识指令重排序指令重排序(InstructionReordering):是现代处理器和编译器优化技术的一部分,旨在提高程序执行效率。通过改变指令的执......
  • GCC在C语言中内嵌汇编 asm __volatile__
    from: https://www.cnblogs.com/hiveme/p/8194832.html在内嵌汇编中,可以将C语言表达式指定为汇编指令的操作数,而且不用去管如何将C语言表达式的值读入哪个寄存器,以及如何将计算结果写回C变量,你只要告诉程序中C语言表达式与汇编指令操作数之间的对应关系即可,GCC会自动插入代码......
  • Volatile不保证原子性及解决方案
    原子性的意义原子性特别是在并发编程领域,是一个极其重要的概念,原子性指的是一个操作或一组操作要么全部执行成功,要么全部不执行,不会出现部分执行的情况。这意味着原子性操作是不可分割的,它们在执行过程中不会被其他操作中断或干扰。原子性的意义在于它保证了数据的一致性和程序......
  • volatile关键字
    volatile可以保证可见性,但不保证原子性:当写一个volatile变量时,JMM会把该线程在本地内存中的变量强制刷新到主内存中去;这个写操作会导致其他线程中的volatile变量缓存无效。volatile会禁止指令重排重排序需要遵守的规则:重排序不会对存在数据依赖关系的操作进行重排......
  • auto,static,const,extern,volatile,register
    auto关键字用于声明变量的生存期为自动,auto修饰的是自动类型的变量,对于局部变量默认就是自动类型的变量,如果没有赋初值它的值就是随机值。static 修饰的变量或者函数有如下特点:static修饰的局部变量,可以延长变量的生命周期(不会被多次初始化)static修饰的全局变量或者函数只......
  • C语言中关键字volatile
     1:什么是volatile?    在C语言中,volatile关键字同样用于修饰变量,volatile告诉编译器该变量的值可能会在程序的控制之外被改变,因此编译器在优化代码时不能对该变量的访问进行优化,比如不能将其缓存到寄存器中,而是每次访问时都需要直接从内存中读取其值。2:变量的访问......
  • volatile关键字解析
    Java并发编程:volatile关键字解析本文转载来自于https://www.cnblogs.com/dolphin0520/​Matrix海子的Java并发编程:volatile关键字解析volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。......
  • Java volatile 深度解析
    简介被volatile修饰的变量有两大特点:当写一个volatile变量时,JMM会把线程对应的本地内存中的共享变量值立即刷新回主内存中。当读一个volatile变量时,JMM会把线程对应的本地内存设置为无效,需要工作线程重新回到主内存中读取最新共享变量。所以volatile的写的内存语......
  • volatile和static的区别
    作用范围和变量类型:static关键字用于创建类级别的变量或方法,所有类的实例共享同一个static变量的副本。它还可以用于方法、初始化块和内部类。相比之下,volatile仅用于声明变量,确保在多线程环境中的可见性,使所有线程都能看到最新的变量值。内存模型:static变量在内存中有......