广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java并发编程之关键字volatile的深入解析
  • 186
分享到

Java并发编程之关键字volatile的深入解析

2024-04-02 19:04:59 186人浏览 独家记忆

Python 官方文档:入门教程 => 点击学习

摘要

目录前言一、可见性二、有序性总结前言 volatile是研究Java并发编程绕不过去的一个关键字,先说结论: volatile的作用:       &n

前言

volatile是研究Java并发编程绕不过去的一个关键字,先说结论:

volatile的作用:

        1.保证被修饰变量的可见性

        2.保证程序一定程度上的有序性

        3.不能保证原子性

下面,我们将从理论以及实际的案例来逐个解析上面的三个结论

一、可见性

 什么是可见性?

举个例子,小明和小红去看电影,刚开始两个人都还没买电影票,小红就先去买了两张电影票,没有告诉小明。小明以为小红没买,所以也去买了两张电影票,因为他们只有两个人,所以他们只能用两张票,这就是小明和小红他俩电影票的数量的可见性。

在讲解之前,我们简单的了解一下JVM当中运行时数据区的结构

堆内存:存放的就是对象,所以它也是JVM当中内存最大的一区域

线程私有区:线程中的栈会去从堆当中获取变量的值来进行操作,正是因为是私有化的,所以两个线程之间的数据是不会共享的

元空间:存放静态变量以及常量还有被虚拟机加载的类信息

同理,我们可以将小明和小红看作java当中的两个线程1和2,共有一个变量


public class volatileTest {
    public static boolean flag = false;
 
    public static void main(String[] args) {
        try {
            new Thread(() -> {
                System.out.println("线程1开始");
                //线程1当中取反值,当flag为true时才会跳出循环
                while (!flag) {
                }
                System.out.println("线程1结束");
            }).start();
            Thread.sleep(100);
            new Thread(() -> {
                System.out.println("线程2开始");
                //线程2给flag赋值
                flag = true;
                System.out.println("线程2结束");
            }).start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

该代码的运行结果如下:

可以很清楚的看到,只有线程2是跑完了的,但是明明线程2已经给flag赋值,线程1并没有停止循环,这就是flag这个变量没有可见性,导致线程1一直不停止

解决的方法有两种

第一:让每个线程空余时间就去堆同步数据(显然不合理)

第二:使用volatile关键字去修饰变量flag

让我们加上volatile试试:

这回线程1总算是成功停止了,由此我们可得,volatile是可以让变量具有可见性的。

学习编程不能只知道如何去使用,而是要知道原理,这样才会有更多的薪资

那么volatile的底层是如何实现的呢?

如上面jvm运行数据区的图所示,所有的变量都是存在了堆当中,而每个线程都是拿到他们的副本进行计算和修改,volatile干了啥事呢,如下图所示

这里我们介绍一个新的概念,叫总线(各位可以把它理解成进行连接线程和堆内存,在计算机的硬件当中,也是有总线的,了解的朋友可以把它用相同概念理解一下)。

当一个被volatile修饰的变量,在某一个线程当中被修改时,总线会监听到这个变动,并且会让其他线程中的这个变量失效,简而言之,当线程2当中堆flag进行了修改,则会导致线程1当中的flag失效,就是把这个线程1当中的flag删了。当线程1中没有flag了,它会重新去获取flag,这个时候,就会使我们的变量flag具有了可见性。

现在我们已经知道了,volatile的实行原理,那么它的底层是如何实现的?

众所周知,java语言加载时  -> class  ->汇编语言 -> 机器语言,因为volatile是个关键字,所以它的底层是一种汇编语法,被volatile修饰的变量其实就是给它加了个一个lock前缀指令。

也就是说,当面试官问到我们,如何手写一个volatile时,我们可以说在编译的层面,添加一个lock前缀指令相当于一个内存屏障,它本身会提供三个功能

        1)它会强制堆缓存的修改操作立即写入主存

        2)如果是写操作,它会导致其他CPU中对应的缓存行无效

        3)它会确保指令重排序时不会吧其它的指令排到内存屏障之前的位置,也不会之前的操作拍到内存屏障之后

前面两点很好理解,并且我们也进行了进一步的认证,第三点可能有朋友不太明白,这就引出了我们下一个论点,volatile可以保证一定的有序性

二、有序性

我们看下面三行代码


int i=1;
int j=2;
i =i++;

在我们的理解当中,程序时自上而下运行的,先是第一行,再是第二行等,然而事实上,jvm可能会对代码进行重排序,比如它可能就会让上面的这三行代码变成下面的状态


int i=1;        
i =i++;
int j =2;

为什么会进行重排序,目的是让代码执行的速度更快,当然它也不是随便乱排的,排序的规则是根据代码的依赖性进行的判断,简而言之就是在不影响结果的情况下进行排序,感兴趣的朋友可以自行去了解一下

这是java本身对程序保证的有序性,在不影响运行结果的情况下进行重排序,但是仅限于单线程的情况下,在多线程的情况中,并不能有效地保证程序的有序性

下图为手写的一个单例模式,不做过多的赘述,左边为代码,右边为翻译的字节码文件

通过上图可以很清晰的看出,new OnlyObject这个操作重点分为了四步,

                第一步:创建这个对象

                第二步:调用这个类的构造方法

                第三步:添加指向(就是从私有线程当中执行堆)

                第四步:加载

由于java对程序的重排序,会使第二步和第三步进行调换位置,在单线程当中不会有任何问题,而在多线程当中就有问题了

看下图代码

当线程1已经完成添加指向时,在堆当中其实已经分配了一个值,但是这时并没有调用构造方法,所以导致此时这个对象只是一个半成品对象 ,里面并不是我们想要的值。这时线程2走进来,他发现object并不为空,所以直接返回了,此时的程序跟我们的业务并不相符,所以我们需要使用volatile来保证我们的有序性。

总结

到此这篇关于java并发编程之关键字volatile的文章就介绍到这了,更多相关Java并发编程关键字volatile内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Java并发编程之关键字volatile的深入解析

本文链接: https://www.lsjlt.com/news/135926.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java并发编程之关键字volatile的深入解析
    目录前言一、可见性二、有序性总结前言 volatile是研究Java并发编程绕不过去的一个关键字,先说结论: volatile的作用:       &n...
    99+
    2022-11-12
  • 详解Java并发编程之volatile关键字
    目录1、volatile是什么?2、并发编程的三大特性3、什么是指令重排序?4、volatile有什么作用?5、volatile可以保证原子性?6、volatile 和 sy...
    99+
    2022-11-12
  • Java并发编程之关键字volatile的示例分析
    这篇文章给大家分享的是有关Java并发编程之关键字volatile的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、作用被 volatile 修饰的变量保证了不同线程对该变量操作的内存可见性禁止指令重排...
    99+
    2023-06-15
  • Java并发编程之关键字volatile知识总结
    目录一、作用二、可见性三、有序性四、happens-before五、与 Synchronized 对比一、作用 被 volatile 修饰的变量 1.保证了不同线程对该变量操作的内存...
    99+
    2022-11-12
  • Java多线程并发编程 Volatile关键字
    volatile 关键字是一个神秘的关键字,也许在 J2EE 上的 JAVA 程序员会了解多一点,但在 Android 上的 JAVA 程序员大多不了解这个关键字。只要稍了解不当就好容易导致一些并发上的错误发生,例如好多人把 volatil...
    99+
    2023-05-31
    java volatile 关键字
  • 如何深入理解Java多线程与并发框中的volatile关键字
    本篇文章为大家展示了如何深入理解Java多线程与并发框中的volatile关键字,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。概念把对 volatile变量的单个读/写,看成是使用 同一个监视器锁 ...
    99+
    2023-06-05
  • JAVA并发中VOLATILE关键字的神奇之处详解
    并发编程中的三个概念: 1.原子性 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行。 2.可见性 对于可见性,Jav...
    99+
    2022-11-12
  • JAVA并发中VOLATILE关键字的示例分析
    小编给大家分享一下JAVA并发中VOLATILE关键字的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!并发编程中的三个概念:1.原子性在Java中,对基本...
    99+
    2023-06-15
  • Java并发编程中volatile关键字有什么作用
    本篇内容主要讲解“Java并发编程中volatile关键字有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java并发编程中volatile关键字有什么作用”吧!1、volatile是什...
    99+
    2023-06-25
  • 深入分析java并发编程中volatile的实现原理
    引言在多线程并发编程中synchronized和Volatile都扮演着重要的角色,Volatile是轻量级的synchronized,它在多处理器开发中保证了共享变量的“可见性”。可见性的意思是当一个线程修改一个共享变量时,另外一个线程能...
    99+
    2023-05-30
    java 并发编程 volatile
  • Java并发编程之Volatile变量详解分析
    目录一、volatile变量的特性1.1、保证可见性,不保证原子性1.2、禁止指令重排二、内存屏障三、happens-beforeVolatile关键字是Java提供的一种轻量级的同...
    99+
    2022-11-12
  • Java并发编程中如何进行从根源上解析volatile关键字的实现
    今天就跟大家聊聊有关Java并发编程中如何进行从根源上解析volatile关键字的实现,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1、解析概览内存模型的相关概念并发编程中的三个概念...
    99+
    2023-06-17
  • 深入源码解析 ReentrantLock、AQS:掌握 Java 并发编程关键技术
    前言Lock重入锁synchronizedReentrantLock ReentrantReadWriteLock 读写锁ReentrantLock 实现原理AQSAQS 内部实现Node 内部结构Node 变更过程添加节...
    99+
    2023-08-16
    java 开发语言 数据库
  • 深入理解Java并发编程之ThreadLocal
    目录ThreadLocal简介ThreadLocal源码解析实现原理ThreadLocalMap源码分析InheritableThreadLocal参考资料ThreadLocal简介...
    99+
    2022-11-13
    Java ThreadLocal
  • 深入解析Python编程中super关键字的用法
    官方文档中关于super的定义说的不是很多,大致意思是返回一个代理对象让你能够调用一些继承过来的方法,查找的机制遵循mro规则,最常用的情况如下面这个例子所示: class C(B): def me...
    99+
    2022-06-04
    关键字 Python super
  • java并发编程关键字volatile保证可见性不保证原子性详解
    目录关于可见性关于指令重排volatile关键字可以说是Java虚拟机提供的最轻量级的同步机制,但对于为什么它只能保证可见性,不保证原子性,它又是如何禁用指令重排的,还有很多同学没彻...
    99+
    2022-11-13
  • 深入理解Java并发编程之LinkedBlockingQueue队列
    前面一篇文章我们介绍了使用CAS算法实现的非阻塞队列ConcurrentLinedQueue, 下面我们来介绍使用独占锁实现的阻塞队列LinkedBlockingQueue。 Lin...
    99+
    2022-11-13
  • java并发编程之深入理解Synchronized的使用
    1.为什么要使用synchronized 在并发编程中存在线程安全问题,主要原因有:1.存在共享数据 2.多线程共同操作共享数据。关键字synchronized可以保证在同一时刻,只...
    99+
    2022-11-12
  • 怎样深入理解Java多线程与并发框中的synchronized 关键字
    怎样深入理解Java多线程与并发框中的synchronized 关键字,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、Class文件与对象对象头 32位JVM的对象头二、sy...
    99+
    2023-06-05
  • Java并发编程之阻塞队列深入详解
    目录1. 什么是阻塞队列2. 阻塞队列的代码使用3. 生产者消费者模型(1)应用一:解耦合(2)应用二:削峰填谷(3)相关代码4.阻塞队列和生产者消费者模型功能的实现1. 什么是阻塞...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作