volatile关键字作用

内存可见性

如何保证内存可见性?
线程操作共享资源时会将资源所在的整个cache line(64byte)从主内存区拷贝到当前线程的工作内存区(CPU缓存)中,当线程1修改变量后,线程1对当前变量的状态被更改为modified,然后将当前变量值写回主内存,同时将其它持有当前变量线程的cache line的状态修改为invalid,当其它线程使用到当前变量时候由于工作内存(CPU缓存)中的值已经为invalid状态,因此需要重新从主内存中读取新的值。以此来实现内存可见性。

示例:

class JCounter {
    int value = 0;
    public void increase() {
        value = 10;
    }
}
public class SyncDemo {
    public static void main(String[] args) {
        JCounter counter = new JCounter();
        
        //t1线程休眠1s后修改值
        Thread t1 = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            counter.increase();
            System.out.println(counter.value + "*********************");
        });
        t1.start();

        //t2线程循环检测变量值
        Thread t2 = new Thread(() -> {
          //while循环检测变量值
            while (counter.value == 0){}
            System.out.println("over");
        });
        t2.start();
    }
}

执行上面代码,发现程序在t1线程修改变量值后,t2线程并无法感知值已经被修改而一直处于循环等待中。
解决方案:只需将JCounter中value变量使用voliate关键字修饰,就能保证value在修改后能及时刷新到主内存以及CPU缓存的更新。

禁止指令重排序

何为指令重排?
众所周知,CPU的计算单元的速度是整个计算机体系结构中最快的单元,CPU的执行所需要的资源、指令需要从内存中获取,但是内存的速度相比于CPU的速度是很慢的,因此CPU在从内存中获取数据的是会出现等待,为了提升CPU的效率,CPU会在这个等待期间执行下一条指令(下一条指令不依赖上一条指令的情况下),因此会出现指令重排序的现象;
volatile关键字会在JVM层级使用内存屏障实现禁止指令重排序,在volatile修饰的变量执行区域的前后插入屏障,屏障内的指令执行必须依次进行,以此实现禁止指令重排序。
屏障指令类型包括:

  • LoadLoad
  • StoreStore
  • LoadStore
  • StoreLoad
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值