Java_volatile_2

本文通过实验展示了在多线程环境下,不使用volatile修饰符时,由于CPU指令重排导致的数据不一致问题,以及使用volatile后如何避免这一问题。通过对比结果,深入理解volatile在保证内存可见性和禁止指令重排方面的作用。

volatile 学习笔记2:

定义静态变量x, y 初始都为0,

开启两个线程,分别把x,y 的值赋值给局部变量 a,b , 并且同时更新x, y 的值, 并把a, b的值保存起来。

会发现两个线程的执行顺序不定,并且同一个线程的两条语句执行的顺序也不一定,导致a,b的值共有4种情况。

其原因是CPU 对指令会重排, 解决方法是给x, y 变量用volatile 修饰,则CPU 不会再进行对它操作的指令重排

    public static int x = 0, y = 0;

    public static void main(String args[]) throws InterruptedException {
        test2();
    }

    private static void test2() throws InterruptedException {
        Set<String> resultSet = new HashSet<>();
        final Map<String, Integer> resultMap = new HashMap<>();

        for (int i = 0; i < 100000; i++) {
            resultMap.clear();
            x = y = 0;
            Thread thread1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    int a = y;
                    x = 1;
                    resultMap.put("a", a);
                }
            });

            Thread thread2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    int b = x;
                    y = 1;
                    resultMap.put("b", b);
                }
            });
            thread1.start();
            thread2.start();
            thread1.join();
            thread2.join();

            resultSet.add("a=" + resultMap.get("a") + ", " + "b=" + resultMap.get("b"));
            System.out.println(resultSet);
        }
    }
[a=1, b=1, a=1, b=0, a=0, b=1, a=0, b=0]
[a=1, b=1, a=1, b=0, a=0, b=1, a=0, b=0]

Process finished with exit code 0

可见其结果 a=1, b=1 这种情况比较少见。

添加Volatile对x, y修饰后

public  volatile static int x = 0, y = 0;

结果:

[a=1, b=0, a=0, b=1, a=0, b=0]
[a=1, b=0, a=0, b=1, a=0, b=0]

Process finished with exit code 0

相应的,Kotlin 上使用关键字 internal 修饰即可

由于参考内容未提及“__ams__ volatile”,推测你想问的是 Java 中的`volatile`关键字。 `volatile`是 Java 中的一个类型修饰符,用于修饰变量。其主要作用有两个方面: - **保证变量的可见性**:在多线程环境下,每个线程都有自己的工作内存,变量的值会被缓存到工作内存中。当一个变量被声明为`volatile`时,它会保证对该变量的写操作会立即刷新到主内存中,而读操作会直接从主内存中读取,从而保证了不同线程之间对该变量操作的可见性。例如,当一个线程修改了`volatile`变量的值,其他线程能立即看到这个修改后的值,而不是使用自己工作内存中旧的缓存值。 - **禁止指令重排序**:在 Java 编译器和处理器为了提高性能,会对指令进行重排序。`volatile`关键字可以禁止特定类型的指令重排序,保证代码的执行顺序符合程序员的预期。例如,在单例模式的双重检查锁定(Double-Checked Locking)中,使用`volatile`关键字可以防止指令重排序导致的问题。 `volatile`的使用场景主要包括: - **状态标记**:当一个变量作为状态标记,用于控制线程的执行流程时,可以使用`volatile`关键字。例如,在一个线程中通过修改一个`volatile`的布尔型变量来通知其他线程停止工作。 ```java public class VolatileExample { private static volatile boolean stop = false; public static void main(String[] args) { new Thread(() -> { while (!stop) { // 执行一些任务 } System.out.println("Thread stopped."); }).start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } stop = true; } } ``` - **单例模式的双重检查锁定**:在实现单例模式时,使用双重检查锁定机制并结合`volatile`关键字可以保证线程安全。 ```java public class Singleton { private static volatile Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值