【volatile关键字】

简介: 【volatile关键字】

volatile关键字

volatile是Java中的关键字,它用于修饰变量,可以保证多个线程修改该变量时的可见性和有序性。下面我们来详细介绍一下volatile关键字。

可见性

当一个线程修改了一个volatile变量的值,其他线程能够立即看到这个变化。这是因为volatile变量会被强制从主内存中读取和写入,而不是从线程的本地内存中读取和写入。举个例子,我们来看一个计数器:

public class VolatileDemo {
    private volatile int counter = 0;
    public void increment() {
        counter++;
    }
    public int getCounter() {
        return counter;
    }
}

在这个计数器中,我们使用了volatile修饰变量counter,当一个线程调用increment()方法时,它会增加counter的值,其他线程可以通过调用getCounter()方法获取到修改后的值。

public class VolatileTest {
    public static void main(String[] args) throws InterruptedException {
        final VolatileDemo demo = new VolatileDemo();
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                demo.increment();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                demo.increment();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("Counter: " + demo.getCounter());
    }
}

在这个测试中,我们创建了两个线程分别对计数器进行10000次累加,最终输出的结果应该是20000。如果不使用volatile修饰变量counter,那么我们无法保证counter的可见性,最终输出的结果可能小于20000。

有序性

volatile变量的修改会被强制立即写入主内存,线程读取变量时也会强制从主内存中读取变量的最新值,因此可以保证volatile变量的有序性。举个例子,我们来看一个生产者消费者模型:

public class VolatileDemo {
    private volatile boolean flag = false;
    private int data;
    public void produce(int data) {
        while (flag) {
            // 等待消费者取走数据
        }
        this.data = data;
        flag = true;
    }
    public int consume() {
        while (!flag) {
            // 等待生产者产生数据
        }
        int result = this.data;
        flag = false;
        return result;
    }
}

在这个模型中,我们使用了volatile修饰变量flag,生产者在生产数据时会将数据写入data变量,然后将flag设置为true;消费者在消费数据时会先等待flag变成true,然后读取data变量的值,最后将flag设置为false。

public class VolatileTest {
    public static void main(String[] args) throws InterruptedException {
        final VolatileDemo demo = new VolatileDemo();
        Thread t1 = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                demo.produce(i);
                System.out.println("Producer produce: " + i);
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                int data = demo.consume();
                System.out.println("Consumer consume: " + data);
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
    }
}

在这个测试中,我们创建了一个生产者线程和一个消费者线程,生产者会生产1到10的数字,消费者会消费这些数字。由于flag变量被volatile修饰,因此我们可以保证生产者和消费者对flag变量的读写是有序的,即先设置值再读取值,从而避免了数据不一致的问题。

总之,volatile关键字用于保证多个线程之间某些变量的可见性和有序性,从而避免了数据竞争和一些隐藏的bug。但是,它并不能保证所有的线程安全问题,例如原子性问题。因此,在需要保证线程安全的代码中,我们需要使用更加强大的锁和同步机制。

小故事

有一个故事是这样的:

有两个小孩在抢玩具,他们会先问对方玩具是否“空闲”,然后才能抢到玩具。如果其中一个小孩没有使用volatile关键字,那么他在查询玩具是否空闲的时候,可能会因为缓存的原因得到一个错误的结果,导致他抢到了被占用的玩具,造成了混乱。但如果他使用了volatile关键字,那么他的查询结果会及时更新到主存中,保证了他拿到的玩具一定是空闲的,不会造成混乱。

这个故事可以帮助理解volatile关键字的底层工作原理:当我们将一个变量定义为volatile类型时,编译器会强制将该变量的读写操作直接从主存中进行,而不是从缓存中进行。这样能保证不同线程之间读取的数据是最新的,避免了由于缓存不一致导致的数据错误。因此,使用volatile关键字能够提高多线程程序的可靠性和稳定性。


相关文章
|
6月前
|
缓存 编译器
volatile关键字
volatile关键字
|
6月前
|
缓存 编译器 C语言
一起来探讨volatile关键字
在C语言中,volatile是一个关键字,用于告诉编译器不要对被声明为volatile的变量做优化,以确保每次对该变量的读写都直接操作内存。
|
存储 缓存 Java
volatile 关键字说明
volatile 关键字说明
51 0
|
3月前
|
缓存 Java 编译器
关键字: volatile详解
综上所述,`volatile`关键字是Java中实现轻量级同步的一个重要手段,主要用于确保变量的跨线程可见性,但并不保证操作的原子性。在多线程编程的过程中,合理地选择和使用 `volatile`关键字,对于提高程序的正确性和性能都至关重要。
40 0
|
存储 Java
浅谈Volatile关键字
该篇文章用来总结笔者对于Volatile关键字的理解,并不会太过深入的探讨。
135 0
浅谈Volatile关键字
|
SQL 缓存 Java
Volatile关键字介绍
Volatile关键字介绍
Volatile关键字介绍
|
缓存 前端开发 Java
volatile关键字有什么用?
volatile关键字有什么用?
volatile关键字有什么用?
|
缓存 安全 算法
你应该知道的 volatile 关键字(上)
不管是在面试还是实际开发中 volatile 都是一个应该掌握的技能。 首先来看看为什么会出现这个关键字。
|
SQL 缓存 安全
volatile 关键字详解(下)
本文主要是讲解 volatile 关键字的使用,首概括它的三大特征,然后引入 JMM 模型,结尾我们解释了单例模式(懒汉模式)中为什么要用 volatile。
154 0
volatile 关键字详解(下)
|
安全 编译器
volatile 关键字详解(中)
本文主要是讲解 volatile 关键字的使用,首概括它的三大特征,然后引入 JMM 模型,结尾我们解释了单例模式(懒汉模式)中为什么要用 volatile。
141 0
volatile 关键字详解(中)