一、什么是Volatile?
Volatile是Java中的一种轻量级的同步机制,用于解决多线程并发访问共享变量时的可见性问题,它保证了对变量的修改能够被立即,且正确的读取到。Volatile在Java内存模型中的作用是用来保证线程间数据的可见性。
二、Volatile关键字的使用
- 声明Volatile变量
Volatile变量的声明格式为:volatile int x = 0;,即在变量之前加上volatile关键字。在Java中,只有共享变量才需要用到它,如果不是共享变量,使用volatile关键字也不会有任何帮助。
- Volatile关键字的特性
① 可见性
如果一个变量被声明为volatile,当一个线程修改了这个变量值时,其他线程能够立即看到最新修改值,而不是使用之前的缓存值。volatile关键字的可见性是通过禁止将数据缓存在寄存器或者其他对线程不可见的地方,以保证多个线程操作主内存中共享变量数据的可见性。
下面是一个示例代码:
public class VolatileVisibilityDemo {
volatile boolean flag = true;
public void changeFlag() {
flag = false;
}
public void print() {
while (flag) {
System.out.println(Thread.currentThread().getName() + "正在运行...");
}
}
public static void main(String[] args) {
VolatileVisibilityDemo demo = new VolatileVisibilityDemo();
new Thread(demo::print, "thread1").start();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
demo.changeFlag();
}
}
在上面的代码示例中,我们首先定义了一个flag变量,并在changeFlag()方法中修改了这个变量的值,然后在print()方法中不断地读取flag变量的值。由于flag变量是volatile类型的,所以当我们修改flag变量的值之后,print()方法中的线程就能立即看到这个最新的修改值,从而退出循环。
如果我们将flag变量修改为非volatile类型的,那么print()方法中的线程可能无法立即看到flag值的最新修改,导致程序在某些情况下无法正确退出循环。
② 禁止指令重排
在Java内存模型中,线程之间的操作是无序的,Java编译器、处理器为了优化程序性能,可能会在不影响单线程执行结果的前提下,对指令进行重排,造成某些结果在多线程的情况下表现出不一致的问题。Volatile关键字可以通过禁止指令重排,来保证线程读写操作的顺序性和可预见性。
下面是一个示例代码:
public class VolatileReorderingDemo {
private int x = 0;
private volatile boolean flag = false;
public void write() {
x = 5;
flag = true;
}
public void read() {
if (flag) {
int y = x + 1;
System.out.println("y = " + y);
}
}
public static void main(String[] args) {
VolatileReorderingDemo demo = new VolatileReorderingDemo();
new Thread(demo::read).start();
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(demo::write).start();
}
}
在上面的代码示例中,我们先启动一个线程来执行read()方法,然后在1秒之后再启动一个线程来执行write()方法。在write()方法中,我们进行了两个操作:1)修改x的值为5;2)将flag标识设置为true。显然的,由于写操作重排到了读操作之后,如果不加Volatile关键字的话,read()方法读到的x值可能是0,而不是5,从而导致程序的输出结果不符合预期。
通过加入Volatile关键字,我们可以禁止将数据缓存在寄存器或其他对线程不可见的地方,保证多个线程操作主内存中共享变量数据的可见性,并且屏蔽JMM所带来的指令重排优化。这样,就可以保证我们在read()方法中读到的x值是最新的,程序的输出结果也符合预期。
三、总结
Volatile是一个十分重要,使用频率比较高的关键字。它可以保证并发操作的正确性和可靠性,并且相比于传统的synchronized关键字,它具有更轻量级的特性和更高的性能,但也由此带来了一些限制,比如说不支持原子性操作。因此,在使用Volatile关键字的时候,我们一定要清楚自己在做什么,并且结合具体的场景,权衡Volatile关键字的使用效果和影响,才能够真正体现出它的价值。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java中Volatile关键字详解及代码示例 - Python技术站