ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Volatile关键字

2021-09-29 10:31:03  阅读:152  来源: 互联网

标签:synchronized ++ 关键字 flag volatile 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之前的代码也会被看到。

标签:synchronized,++,关键字,flag,volatile,Volatile,赋值
来源: https://blog.csdn.net/Chengzheng119/article/details/120531439

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有