线程安全——内存可见(volatile)


import java.util.Scanner;

public class Demo16 {
    static class Counter{
        public int count = 0;
    }
    //t1读数据,t2改数据
    public static void main(String[] args) {
        Counter counter = new Counter();
        Thread t1 = new Thread(()->{
            while(counter.count==0){

            }
            System.out.println("t1执行结束");
        });
        t1.start();
        Thread t2 = new Thread(()->{
            System.out.println("请输入一个int: ");
            Scanner scnner = new Scanner(System.in);
            counter.count = scnner.nextInt();
        });
        t2.start();
    }
}

这段代码运行完会发现输入后线程没有结束。原因如下:

在t1中执行的while循环这个操作“counter.count == 0”在操作系统中分为两步:读内存(LOAD),比较(CMP);而while循环转的很快,这就意味着要多次进行LOAD和CMP。而比较可比读内存快多了,而且每次读的结果还是同一个。所以这时编译器就只执行一次load,后续CMP就不用重新读内存了(编译器优化)。而运行到t2的时候,count已经变成了我们输入的值,此时内存已经被修改了。而t1由于只读了一次内存所以并没有发现内存已经被修改。所以,进程结束不了。

为了解决问题,我们需要用关键字提醒编译器此处无需编译器优化。这就是volatile的作用。

volatile:用来修饰一个变量。此时被修饰的变量,编译器就不会做出“不读内存只读寄存器”这样的优化。

谈到volatile,就得先讲讲JMM(java Memory Model Java内存模型)了

volatile禁止了编译器优化,避免了直接读取CPU中寄存器(工作内存)中缓存的数据,而是每次都重新读内存(主内存)

ps:主内存才是真的内存。工作内存不是!他只是个存储区。

正常程序执行的过程中,会把主内存的数据,先加载到工作内存中,再进行计算处理。

编译器优化可能会导致不是每次都真的读取主内存,而是直接取工作内存中的缓存数据。(就可能导致内存可见性问题)

所以volatile 起到的效果, 就是保证每次读取内存都是真的从主内存重新读取~

修改后就对了

但是,volatile只能保证内存可见性而原子性不行。 

public class Demo17 {
    static class Counter{
        volatile static public int count = 0;
        public void increase(){
            count++;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Counter counter = new Counter();
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                counter.increase();
            }
        });

        Thread t2 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                counter.increase();
            }
        });
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(Counter.count);

    }

}

可以看到结果不是10000。(这段代码是在synchronized的博客中讲的,可以去看看啊ヾ(•ω•`)o)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值