Volatile关键字


Volatile关键字的作用:

        预防可见性问题,重排序问题。

Volatile是一种同步机制,比synchronized或者Lock相关类更轻量,因为使用Volatile并不会发生上下文切换等开销很大的行为。

        一个变量被修饰成volatile,JVM就知道了这个变量可能会被并发修改。

但是,volatile是一个轻量级的,对应的能力也小,无法像synchronized一样能够对变量进行原子保护。volatile仅在很有限的场景下才能发挥作用。

        案例: 不适用于多线程a++计数。

案例2: boolean flag ,如果一个共享变量自始至终只被各个线程赋值,而没有其他的操作,那么就可以用volatile来代替synchronize或者代替原子变量,因为赋值自身是有原子性的,而volatile又保证了可见性,所以就足以保证线程安全。

        注意:这个赋值是单纯的赋值,不能依赖前提条件。

package JMM;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @program:多线程和IO
 * @descripton:
 * @author:ZhengCheng
 * @create:2021/9/28-16:23
 **/
public class WithVolatile implements Runnable{
    volatile boolean flag = true;
    AtomicInteger real = new AtomicInteger();
    public static void main(String[] args) throws InterruptedException {
        WithVolatile v = new WithVolatile();
        Thread thread1 = new Thread(v);
        Thread thread2 = new Thread(v);
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        System.out.println(v.flag);
        System.out.println(v.real);
    }
    @Override
    public void run() {
        for (int i = 0; i < 10000; i++) {
            setFlag1();//correct;
            //setFlag2();//不对
            real.incrementAndGet();
        }
    }
    private void setFlag1(){
        flag = false;
    }
//不适用
    private void setFlag2() {
        flag = !flag;
    }
}


首先我们应当知道,volatile有什么样的作用。Volatile有如下两点作用

        1.可见性,保证在读取一个volatile变量之前,需要先使相应的本地缓存失效,这样就必须到主内存读取最新值,写一个volatile属性会立即刷入到主内存。

        2.禁止指令的重排序优化:解决单例双重锁乱序问题

Volatile的适用场景:

        1.单纯的赋值场景 (注意,a++并不适合!)

明明volatile可以保证我们读取到最新值,那为什么会有a++问题呢?

因为我们知道,在JMM里,Volatile只保证我们读的值是正确的,但是假设此时T1和T2都读到a=1,在发生各自线程的自增之后,a=2,尽管其迅速的刷入了内存之中,但是我们得到的还是a=2,使得++操作少了一次。

        2.触发器

那么Volatile和Synchronized有什么关系?

        Volatile可以看做是轻量级的Synchronized:如果一个共享变量自始至终只有赋值操作,而没有复杂操作,那么就可以用volatile来代替synchronized来代替原子变量,因为赋值自身是有原子性的,而volatile又保证了可见性,在仅仅赋值的多线程的操作里,是足够保证线程安全的。

Volatile小结

1.volatile修饰符使用场景(2个)

2.volatile的读写操作是无锁的,不能像synchronized一样,所以它没有提供原子性和互斥性,导致volatile++是不安全的。但也正因为无锁,不需要花费时间在释放锁上,其花费是很低的。

3.volatile只能作用在属性上,而不像synchronized可以作用与一个方法上。

4.volatile保证了可见性的问题,在JMM得规范下,可以直接刷入主存。

5.volatile提供了happens-before,只要 写入了,就一定能够读到最新值。

6.volatile可以使得long和double的赋值是原子的。

Synchronized的理解

1.Synchronized不仅保证了原子性,还保证了可见性。

2.Synchronized不仅让被保护的代码安全,还近朱者赤。synchronized之前的代码也会被看到。

上一篇:JMM、数据同步以及并发编程的三大问题


下一篇:2021-09-27错题