5

Java中的Volatile到底是什么?

 8 months ago
source link: https://www.51cto.com/article/769376.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Java中的Volatile到底是什么?

作者:Reathin 2023-10-11 08:29:54
volatile只能修饰变量,而后者可以修饰方法,语句块。volatile不能保证原子性,而后者是可以保证原子性的。都可以保证可见性,但原理不同,volatile是对变量加了Lock,而后者使用monitorEnter和monitorExit。volatile不会引起阻塞,而后者会。在一些场景下使用volatile性能是要更好地。
图片
图片

volatile是什么?

"volatile"是一个关键字,用于修饰变量。它的作用是告诉编译器该变量可能会在意料之外的时候被修改,因此编译器在对该变量进行优化时需要特别小心。

具体来说,当一个变量被声明为"volatile"时,编译器会禁止对该变量进行某些优化,以确保每次访问该变量时都会从内存中读取最新的值,而不是使用之前缓存的值。这对于多线程编程或者与硬件交互的程序非常重要,因为在这些情况下,变量的值可能会被其他线程或者硬件设备修改。

需要注意的是,"volatile"关键字只能保证变量的可见性,不能保证原子性。如果需要保证原子性,还需要使用其他的同步机制,比如互斥锁或原子操作。

总结起来,"volatile"关键字用于修饰变量,告诉编译器该变量可能会在意料之外的时候被修改,从而禁止对该变量进行某些优化,确保每次访问变量时都会从内存中读取最新的值。

在Java中,关键字volatile用于修饰变量,用来确保多个线程之间对该变量的可见性和顺序性。

当一个变量被声明为volatile时,它的值将会被存储在主内存中,而不是线程的本地内存中。这样,当一个线程修改了该变量的值时,其他线程可以立即看到最新的值,而不是使用本地缓存中的旧值。

此外,volatile关键字还可以防止指令重排序,即保证了对该变量的操作按照代码的顺序执行,不会发生乱序执行的情况。

需要注意的是,volatile关键字只能保证可见性和顺序性,并不能保证原子性。如果需要保证原子性,可以考虑使用synchronized关键字或java.util.concurrent.atomic包中的原子类。

volatile作用

在Java中,volatile的作用是确保多个线程之间对该变量的可见性和有序性。具体来说,volatile的作用有以下几点:

  1. 可见性:当一个线程修改了volatile修饰的变量的值时,其他线程能够立即看到最新的值。这是因为volatile修饰的变量会被存储在主内存中,而不是线程的本地缓存中,从而保证了可见性。
  2. 有序性:volatile修饰的变量的读写操作具有顺序性。也就是说,当一个线程对volatile变量进行写操作后,其他线程在读取该变量时,会按照写操作的顺序来读取,不会出现乱序的情况。

volatile关键字在多线程编程中起到了重要的作用,可以用来确保变量的可见性和有序性,从而避免了由于线程间的竞争而引发的一些问题。

原子性是指一个操作要么完全执行,要么完全不执行,不会出现部分执行的情况。原子性是并发编程中的一个重要概念,用于确保多个线程或进程之间的操作不会相互干扰。

在并发编程中,多个线程或进程可能同时访问共享资源,如果没有保证原子性,就可能导致数据不一致或竞态条件等问题。为了保证原子性,可以使用锁、互斥量、原子操作等机制来控制对共享资源的访问。

在数据库中,原子性也是一个重要的概念。原子性要求数据库的操作要么全部执行成功,要么全部不执行,不会出现部分执行的情况。数据库中的事务就是为了保证原子性而设计的,事务可以将一组操作作为一个不可分割的单元进行执行,要么全部执行成功,要么全部回滚。

在计算机科学中,可见性通常指的是在多线程或并发编程中,一个线程对于其他线程的操作是否可见。可见性问题是由于多线程的执行顺序不确定性而引起的,当一个线程对共享变量进行修改后,其他线程可能无法立即看到这个修改,导致数据不一致或错误的结果。

为了提高程序的执行效率,编译器对编译后的指令进行重排序,即代码的编写顺序不一定就是代码的执行顺序。

并发编程只有同时满足这三大特性,才能保证程序正确的执行,而volatile只保证了可见性和有序性,不保证原子性。

volatile的作用只有两个

  • 保存内存的可见性
  • 禁止JVM内存重排序(保证有序性)

在并发多线程情况下,为什么会有可见性问题?如果不做控制,为什么一个线程修改了共享变量的值,其他线程不能立即看到。这里就需要了解JMM(JAVA内存模型,JAVA memory model)

由于JAVA共享变量是存储在主内存中,而JAVA线程是无法直接访问主内存数据,只能把主内存的数据拷贝一份副本,修改完本地内存的数据,再写回主内存,而此时另一个线程也把主内存的数据拷贝到自己私有的本地内存中,虽然线程1已经修改了主内存数据,但线程2却无法感知到,所以就出现了内存可见性问题。

可见性实现原理

当一个共享变量声明为volatile后,会有以下效果:

  • 当写一个volatile变量时,JMM会把该线程对应的本地内存中的变量强制刷新到主内存中去。
  • 这个写回操作会导致其他线程的缓存无效。

(volatile主要通过汇编lock前缀指令,它会锁定当前内存区域的缓存行,并且立即将当前缓存行数据写入到主内存中耗时非常短),回写主内存的时候会通过MESI协议使其他线程缓存了该变量的地址失效,从而导致其他线程需要去主内存中重新读取数据到工作线程中。)

有序性保证的原理:它是通过插入内存屏障,在内存屏障前后禁止重排序优化,以此实现有序性。

volatile应用场景

它可以保证可见性和有序性,但无法保证原子性,所以它的应用场景不如synchronized广泛,主要有两个场景:一个是做状态变量,二是做需要重新赋值的共享对象。

vloatile与synchronized的区别

volatile只能修饰变量,而后者可以修饰方法,语句块。volatile不能保证原子性,而后者是可以保证原子性的。都可以保证可见性,但原理不同,volatile是对变量加了Lock,而后者使用monitorEnter和monitorExit。volatile不会引起阻塞,而后者会。在一些场景下使用volatile性能是要更好地。

volatile使用条件

对变量的写操作不依赖当前值:比如i++操作,变量的写操作依赖安全值,所以不能保证线程安全。该变量没有包含在具有其他变量的不变式中。比如i<value,即使i变量声明为volatile,也不能保证线程安全,因为value可能在运行时候的判断发生变化。

责任编辑:武晓燕 来源: 沐雨花飞蝶

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK