栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

十、volatile

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

十、volatile

一、原理
  • 底层实现是内存屏障,Memory Barrier(Memory Fence)
1. 可见性 1.1 写屏障(sfence)
  • 被voliate修饰的变量,会在写操作后,加上写屏障
  • 在该屏障之前的所有改动,都会同步到主存中去
package com.dreamer.multithread.day02;

public class Demo03 {

    private static int number = 0;

    private static volatile int age = 0;

    public static void main(String[] args) {

        new Thread(() -> {
            
            number++;
            age++;
            // JVM  会加上写屏障
        }).start();

    }
}
1.2 读屏障(sfence)
package com.dreamer.multithread.day02;

public class Demo03 {

    private static int number = 0;

    private static volatile int age = 0;

    public static void main(String[] args) {
        
        new Thread(() -> {

            
            // JVM 会加上读屏障
            int numberResult = number;
            int ageResult = age;
        }).start();

    }
}
2. 有序性
  • 防止指令重排
  • 只能针对本线程内不会发生指令重排
2.1 写屏障(sfence)
  • 写屏障会将保证屏障上面的代码不会重排,也就是说不会将屏障上面的代码挪到屏障下面执行
2.1 读屏障(sfence)
  • 上述一样的道理
3. 不能保证指令交错
  • volatile不能保证不同线程在执行的时候的指令交错引发的问题
  • 因为它只是保证各个线程在执行的时候都从主存中去加载
  • 保证指令不会发生交错: 用synchronized来进行枷锁
二、happen-before原则
  • 规定了对共享变量的写操作,对其他线程的读操作的可见性总结
  • 是可见性和有序性的一套总结
1. synchronized
  • 线程解锁m之前对变量的写,对于接下来的用m加锁的其他线程的读,改变是可见的
package com.dreamer.multithread.day02;

public class Demo04 {
    private static int x = 0;

    private static Object lock = new Object();

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (lock) {
                x = 10;
            }
        }).start();

        new Thread(() -> {
            synchronized (lock) {
                System.out.println(x);
            }
        }).start();
    }
}
2. volatile
  • 变量用volatile修饰,一个线程对其的修改,对于其他线程来说是可见的
package com.dreamer.multithread.day02;

public class Demo05 {
    private static volatile int x = 0;

    public static void main(String[] args) {
        new Thread(() -> x = 10).start();

        new Thread(() -> System.out.println(x)).start();
    }
}
3. 起步
  • 线程start前对变量的写操作,对该线程开始后的读操作是可见的
package com.dreamer.multithread.day02;

public class Demo06 {
    private static int x = 0;

    public static void main(String[] args) {

        x = 10;

        new Thread(() -> System.out.println(x)).start();
    }
}
4
  • 线程结束前对变量的写操作,对其他线程得知它结束后的读操作可见性(如调用join方法)
package com.dreamer.multithread.day02;

public class Demo07 {

    private static int x = 0;

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

        Thread thread = new Thread(() -> x = 10);
        thread.start();

        thread.join();

        System.out.println(x);
    }
}
5. 默认值
  • 对变量默认值的写,0,false,null,其他线程对该变量可见
6. 传递性
  • 其实就是volatile的读屏障和写屏障问题
package com.dreamer.multithread.day02;

public class Demo08 {
    private static int x = 0;

    private static volatile int y = 0;

    public static void main(String[] args) {
        new Thread(() -> {
            x = 10;
            y = 20;
            // 写屏障,会将上面的操作全部赋值到主存中去
        }).start();

        new Thread(() -> {
            System.out.println(x);
            System.out.println(y);
        }).start();
    }


}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/305972.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号