教育行业A股IPO第一股(股票代码 003032)

全国咨询/投诉热线:400-618-4000

为什么volatile能保证变量对所有线程的可见性?

更新时间:2023年04月25日09时33分 来源:传智教育 浏览次数:

好口碑IT培训

  在计算机程序中,当多个线程同时访问同一个变量时,可能会发生线程安全问题,其中之一是变量的可见性问题。这意味着一个线程在修改了一个变量的值之后,其他线程无法立即感知到这个变化,导致程序出现不一致的行为。

  为了解决这个问题,Java提供了一个关键字volatile。使用volatile关键字声明的变量,其特点如下:

  1.可见性:对于一个volatile变量的写操作,JVM会立即把修改后的值刷新回主内存中,而不是仅仅保留在本地缓存中。这样,其他线程就能够看到该变量的最新值,从而避免了可见性问题。

为什么volatile能保证变量对所有线程的可见性?

  2.禁止指令重排:volatile关键字还可以禁止JVM对指令的重排优化。在不加volatile关键字的情况下,JVM为了提高性能,可能会对指令进行重排,导致程序出现意外的行为。而使用volatile关键字声明的变量,JVM会保证指令的执行顺序和程序的代码顺序一致,从而避免了这种问题。

  接下来,我们通过一段代码来演示下volatile关键字如何保证可见性:

public class VolatileDemo {
    private volatile boolean flag = false;

    public void setFlag() {
        flag = true;
    }

    public void printFlag() {
        System.out.println("flag = " + flag);
    }

    public static void main(String[] args) {
        final VolatileDemo demo = new VolatileDemo();

        new Thread(() -> {
            try {
                Thread.sleep(1000); // 模拟线程1执行时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            demo.setFlag();
        }).start();

        new Thread(() -> {
            while (!demo.flag) { // 如果flag不是volatile,该循环可能会一直执行下去
                // do nothing
            }
            demo.printFlag();
        }).start();
    }
}

  在这个代码中,我们声明了一个名为flag的布尔型volatile变量。在程序启动后,我们启动了两个线程,线程1会在1秒后将flag的值设为true,线程2会在flag变为true之前一直循环等待。由于flag是volatile类型,线程2能够正确感知到flag的变化,从而在flag变为true后打印出相应的信息。如果flag不是volatile类型,线程2可能会一直等待下去,因为它无法感知到flag的变化,从而导致程序出现错误的结果。

  需要注意的是,volatile关键字虽然可以保证可见性和禁止指令重排,但并不能保证原子性。也就是说,如果一个变量被多个线程同时访问,并且这些线程都对它进行修改操作,那么使用volatile关键字并不能保证程序的正确性。这时候需要使用其他的线程同步机制,如synchronized关键字或者Lock接口等。

0 分享到:
和我们在线交谈!