volatile分析(可见性、无原子、禁重排)

volatile是什么

volatile:JVM提供的轻量级的同步机制

volatile的特点

可见性(及时通知其他线程主物理内存的值已经改变)
原子性无保证
有序性(禁止指令重排)

1.可见性
//模拟服务器,服务器运行接收到信号后stop
class Server{
    private static volatile boolean isStop;
    public static void stop(){ isStop=true;}
    public static void run(){while(!isStop){}} //服务器运行

    public static void main(String[] args) throws InterruptedException {
        new Thread(Server::run,"t1").start();
        TimeUnit.SECONDS.sleep(2);
        new Thread(Server::stop,"t2").start();//服务器收到了stop信号
    }
}
若变量isStop省略修饰符volatile,则程序无法停止
原因:线程t2修改isStop后其余线程不可见

注:volatile的实现依赖于CPU的缓存一致性协议

2.原子性

卖票时,所有线程同时拿到了同一数据,线程1修改后将数据写回主物理内存时被挂起,线程2将修改的数据写回主内存,并通知其他线程主物理内存中的值已改变,但线程1此时唤醒,在收到通知前将数据写回了主物理内存,出现了丢失写值(写覆盖)的现象
解决方案:
1>加同步锁
2>使用JUC下的原子操作(如:AtomicInteger等),可保证程序的原子性(原理是CAS+volatile)

class Main{
    AtomicInteger num=new AtomicInteger();
    CountDownLatch count=new CountDownLatch(20);
    public  void method() {
        count.countDown();
        for(int i=0;i<200;i++)   num.getAndIncrement();
    }
    public static void main(String[] args) throws InterruptedException {
        Main m=new Main();
        for(int i=0;i<20;i++) { new Thread(m::method).start(); }
        m.count.await();
        System.out.println(m.num);
    }
}
运行结果:4000,若num采用int类型,则结果<=4000
原因:num++不是原子性操作,但我们利用了JUC下的原子操作AtomicInteger
3.有序性
synchronized有序因为其只有单个线程在执行,发生指令重排一般也没有关系
volatile禁止指令重排保证了有序性
class Singleton{
    private static volatile Singleton obj;
    private Singleton(){};
    public static Singleton getInstance(){
        // B线程检测到obj不为空在此处返回变量尚未被初始化的对象
        if(obj==null){
            synchronized (Singleton.class){
                if(obj==null){ obj=new Singleton(); }// A线程被指令重排,obj被赋值但其变量未被初始化
            }
        }
        return obj;
    }
}:在JVM中对象创建分三步,申请内存、成员变量初始化、将指针指向堆内存中对象,23可能会发生指令重排序


指令重排在编译器认为这是一种优化,但若我们的程序在多线程中使得数据的一致性无法保证
禁止指令重排,即禁止指令重排优化,避免在多线程环境下出现执行乱序的情况

附加知识点:CAS

为什么Atomic可解决原子性?
解:底层是CAS,详情见CAS详解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值