Java中的volatile

Java中的volatile

  • Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程。当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。

Java 内存模型

  • JMM(Java Memory Model):Java 内存模型,是 Java 虚拟机规范中所定义的一种内存模型,Java 内存模型是标准化的,屏蔽掉了底层不同计算机的区别。也就是说,JMM 是 JVM 中定义的一种并发编程的底层模型机制。
  • JMM 的规定:
    1.所有的共享变量都存储于主内存。这里所说的变量指的是实例变量类变量,不包含局部变量,因为局部变量是线程私有的,因此不存在竞争问题。
    2.每一个线程还存在自己的工作内存,线程的工作内存,保留了被线程使用的变量的工作副本。
    3.线程对变量的所有的操作(读,取)都必须在工作内存中完成,而不能直接读写主内存中的变量。
    4.不同线程之间也不能直接访问对方工作内存中的变量,线程间变量的值的传递需要通过主内存中转来完成。

volatile保证可见性

  • 可见性:多个线程共同访问共享变量时,某个线程修改了此变量,其他线程能立即看到修改后的值。
public class demo5 {

    //volatile保证可见性
    //当对volatile变量执行写操作后,JMM会把工作内存中的最新变量值强制刷新到主内存
	//写操作会导致其他线程中的缓存无效
	//这样,其他线程使用缓存时,发现本地工作内存中此变量无效,便从主内存中获取,这样获取到的变量便是最新的值,实现了线程的可见性。
    volatile static int number = 0;
    public static void main( String[] args ) throws InterruptedException
    {
        
       new Thread(() -> {
           while(number == 0){

           } 
       }).start();

       TimeUnit.SECONDS.sleep(2);

       number = 1;
       System.out.println(number);
    }
}

volatile不保证原子性

  • 原子性: 一个操作或者多个操作,要么全部执行成功,要么全部执行失败。满足原子性的操作,中途不可被中断。
public class demo6 {

    //volatile不保证原子性
    private static volatile int number=0;

    public static void add() {
        number++;//不是原子性操作
        //在内存中的操作有三步,通过反编译字节码文件可以知
        //1.获取number值
        //2.number值+1
        //3.写回number值
    }

    public static void main( String[] args )
    {
        for(int i=0;i<30;i++){
            new Thread(() -> {
                for(int j=0;j<1000;j++){
                    add();
                }
            }).start();
        }

        while(Thread.activeCount()>2){
            Thread.yield();//线程礼让
        }

        System.out.println(Thread.currentThread().getName() + " "+ number);
    }
}
  • 上面例子除了使用lock和synchronized保证原子性之外,还可以使用原子类
public class demo6 {

    //volatile不保证原子性
    //AtomicInteger原子类的Integer
    private static AtomicInteger number = new AtomicInteger();

    public static void add() {
        // number++;//不是原子性操作
        //在内存中的操作有三步,通过反编译字节码文件可以知
        //1.获取number值
        //2.number值+1
        //3.写回number值

        number.getAndIncrement();//+1方法  底层原理cas  不加锁lock和synchronized,可以通过原子类解决原子性操作
    }

    public static void main( String[] args )
    {
        for(int i=0;i<30;i++){
            new Thread(() -> {
                for(int j=0;j<1000;j++){
                    add();
                }
            }).start();
        }

        while(Thread.activeCount()>2){
            Thread.yield();//线程礼让
        }

        System.out.println(Thread.currentThread().getName() + " "+ number);
    }
}

volatile防止指令重排序

  • 有序性:程序执行的顺序按照代码的先后顺序执行。
  • 指令重排序:由于JMM模型中允许编译器和处理器为了效率,进行指令重排序的优化。指令重排序在单线程内表现为串行语义,在多线程中会表现为无序。
  • volatile是通过编译器在生成字节码时,在指令序列中添加“内存屏障”来禁止指令重排序的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值