Android volatile 原理。

2020-12-04  本文已影响0人  ZSGZ_AD

在《Java 并发编程:核心理论》一文中,我们已经提到可见性、有序性及原子性 问题,通常情况下我们可以通过 Synchronized 关键字来解决这些个问题,不过 如果对 Synchonized 原理有了解的话,应该知道 Synchronized 是一个较重量级 的操作,对系统的性能有比较大的影响,所以如果有其他解决方案,我们通常都 避免使用 Synchronized 来解决问题。

而 volatile 关键字就是 Java 中提供的另一种解决可见性有序性问题的方案。对于 原子性,需要强调一点,也是大家容易误解的一点:对 volatile 变量的单次读/ 写操作可保证原子性的,如 long 和 double 类型变量,但是并不能保证 i++这种 操作的原子性,因为本质上 i++是读、写两次操作。 volatile 也是互斥同步的一种实现,不过它非常的轻量级。 volatile 的意义? 线程会一直等待。 可以尝试获得锁,线程可以不用一直等待 锁状态 无法判断 可以判断 锁类型 可重入 不可中断 非公平 可重入 可判断 可公平(两者皆可) 性能 少量同步 大量同步

    private volatile int start = 0;
    private void volatile Keyword() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    start++;
                }
            }
        }; for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(runnable); thread.start();
        } Log.d(TAG, "start = " + start);
    }
image.png

这段代码启动了 10 个线程,每次 10 次自增,按道理最终结果应该是 100,但是 结果并非如此。 为什么会这样?
仔细看一下 start++,它其实并非一个原子操作,简单来看,它有两步:
1、取出 start 的值,因为有 volatile 的修饰,这时候的值是正确的。
2、自增,但是自增的时候,别的线程可能已经把 start 加大了,这种情况下就有 可能把较小的 start 写回主内存中。
所以 volatile 只能保证可见性,在不符合以 下场景下我们依然需要通过加锁来保证原子性:

上一篇 下一篇

猜你喜欢

热点阅读