volatile 详解

news2024/9/22 6:04:39

1. 前言

  • 在并发编程的过程中,volatile属性非常重要。
  • 首先我们要了解并发编程的三大特性:可见性, 有序性, 原子性
  • 而我们今天的了解的volatile 就牵扯到可见性, 有序性
  • 同时我也会从个人了解的角度给大家分析下,如果有什么不对的地方也希望大家在评论区指正

2. 适合人群

  • 线程的初学者

3. 可见性

大家可以先看一段代码,自己想想到底会有什么执行结果:

private static boolean flag = true;

    public static void test01() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (flag) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        t1.start();
        Thread.sleep(2000);
        flag = false;
    }

也许有的人会给出答案说,执行2秒后,就会停止。但是事实会是这样吗?? 大家可以手动执行下。

3.1 内存可见性

针对上述的代码,既然已经提出来了结果肯定不会是正常结束的。那为什么会这样呢???

在这里插入图片描述

  • 这里面会牵扯到线程缓存的事情。
  • 当线程执行的时候,会将使用到的值进行拷贝,拷贝到线程的缓存中。所以我们修改值后其实修改的是主内存的值,跟线程的缓存的值无任何关系。所以就算你修改了值while循环也是不会停止的。 所以这个就是线程的可见性。最起码线程跟主线程之前的内存不可见的
  • 所以我们的目的就是为了让"它"可见

3.2 volatile 属性

private static volatile boolean flag1 = true;

    public static void test02() throws InterruptedException {
        Thread t1 = new Thread(() -> {
           while (flag1) {
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }
        });

        t1.start();
        Thread.sleep(1000);

        flag1 = false;
    }
  • 大家可以运行上述的代码,实际执行的结果跟我们预想的是一致的。
  • 为什么会出现这种情况呢??? 其实我们仔细观察就会发现 控制循环的变量,是被修饰符volatile 进行修饰的。
  • 这意味着当线程用到变量flag1 的时候,都会从主内存中查找,如果子线程修改了值,同样会通过刷新的形式同步到主内存中。所以这就体现了线程的可见性

3.3 volatile 修饰引用类型

    static class A {
        boolean running = true;
        void m() {
            System.out.println("程序开始...");
            while (running) {}
            System.out.println("程序结束...");
        }
    }

    static private volatile A a = new A();

    public static void test03() throws InterruptedException {
        new Thread(a::m, "t1").start();
        Thread.sleep(1000);
        a.running = false;
    }

看如上实例,结果是:实际的结果跟期望的结果不同,这是为什么呢。因为:如果volatile修饰引用类型的话,引用类型本身可见,但是内部属性是不见的

3.4 我们只能用volatile 来修饰吗

    public static void test04() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (flag) {
                try {
                    System.out.println("执行中...");
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        t1.start();
        Thread.sleep(1000);
        flag = false;
    }
  • 通过上述的实例可以得知,其实这么写也是可以的正常执行的。那为什么呢???
  • 其实因为我们添加了System.out.println("执行中...");. 这么神奇吗??? 接下来让我们看下println 源码的实现

在这里插入图片描述
通过上述的截图没看错,锁synchronized 也是设置线线程可见性的

4. 顺序性

你以为程序的执行是顺序的吗??? 不,理解错了不是你以为的就是你以为的。有时候 我们程序执行的时候是乱序的。

4.1 为什么是乱序的

在这里插入图片描述

  • 什么情况下都可以乱序吗???

如果不影响单线程的最终一致性的话,都有可能进行乱序执行。执行的目的还是提高效率

  • volaitile 是如何阻止乱序的

在这里插入图片描述

  • 每个实现jjvm底层的中间件,都必须实现JVM内存屏障
  • volatile 底层就是基于内存屏障来防止乱序的

5. 结束

  • 上述的只是对volatile的使用场景,以及解决问题进行讲解。
  • 但是对乱序并没有做过多解释。第一呢,怕误人子弟,第二呢,感觉不是几个实例就能说清楚的。其实可以理解为就算n++ 这么一句话,翻译成JVM识别的语句,以及底层识别的语句都会转换成很多语句。在多线程的模式下,任何语句执行都会被打断,从而导致乱序执行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/132496.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

物联网与射频识别技术,课程实验(一)

目录 (1)communication.py (2)Reader.py (3)Tag.py 实验1—— EPC C1G2标准下的标签状态转换仿真 实验说明: 利用Python或Matlab模拟C1G2标签的状态转换模型; 程序应能显示标签…

深度学习:01 神经网络与激活函数

目前,最广泛使用的定义是Kohonen于1988年的描述: 神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够模拟生物神经系统对真实世界物体所做出的交互反应。 目录 对神经网络的概述 神经网络的表示 激活函数 为什么激…

2022年总结:从初二学生到算法作者的蜕变之路

目录 一年的创作历程 我和 CSDN 在编程竞赛的合作 About CBC 技术社区的发展 夜跑奇遇 About 博客之星 新年致谢 元旦祝福 一年的创作历程 2022年,这一年对于我来说是十分重要的一年。在这一年里,我作为一名初二在校学生,在CSDN上发布…

【Linux 环境变量】环境变量一般是指在操作系统中用来指定操作系统运行环境的一些参数

1.问题:为什么自己写的程序需要加上./才能执行,但是指令可以直接使用,例:ls -al? 因为:不加"./"执行程序的时候会按环境变量PATH里面的各个路径找到就正常执行,找不到就报错&#xff…

SQL笔试题总结

文章目录前言一、列转行题目:将表Student转化为下面的形式展示先放答案逐步剖析二、row_number() over() 的使用题目:统计订单交易表(orders)每个商品交易金额最高的那一条数据先放答案逐步剖析三、逐行累加题目:还是订…

✿✿✿JavaScript --- jQuery框架二

目 录 1.高级事件 (1)浏览器一打开自动触发我们绑定的事件 (2) Trigger 传递数据 (3)自定义事件 (4)trigger 简写方案 (5)triggerHandler() (6)trigger和triggerHandler的区别 (7)on off one 2.动画 (1)显示 隐藏 动画 (2)队列动画 (3)下滑 上卷 (4)淡入淡出…

Nacos启动出现Error creating bean with name ‘memoryMonitor‘ 、‘externalDumpService‘

目录 🧡问题 🧡解决方法 💟这里是CS大白话专场,让枯燥的学习变得有趣! 💟没有对象不要怕,我们new一个出来,每天对ta说不尽情话! 💟好记性不如烂键盘&#x…

WSL2支持systemctl命令

文章目录背景相关知识systemdinit安装方法一:微软官方支持方法(推荐)方法二:安装daemonize实现参考背景 微软官方推出Windows Terminal第一时间,我就安装了这个终端软件。现在GitHub已经有86.8k星,且发布了…

一名普通Java程序员的2022的总结和2023的展望

前言今天是元旦节,也是2023年的第一天,首先祝各位亲朋好友们元旦快乐,在新的一年全家身体康健,诸事顺遂,阖家幸福,最重要的是身体健康,工作顺利,永无BUG永不加班!&#x…

计算机组成原理【1】初识硬件

目录 考点1:硬件发展———————————————————————————— 一.计算机硬件的基本组成 1.早期冯诺依曼机 (1)冯.诺依曼计算机的特点: 2.现代计算机的结构 3.总结图 二.各个硬件的工作原理 1.寄存器MAR,MDR 2.主存…

EMNLP22 外部知识注入:Prompt-Learning for Short Text Classification

Prompt-Learning for Short Text Classification 任务形式:短文本分类问题,但是短文本的短长度、特征稀疏性和高模糊性给分类任务带来了巨大挑战。 1以往的工作,在注入外部信息上 大多数提示学习方法手动扩展标签词或仅考虑类别名称以纳入…

得分_UVa1585分子量_UVa1586数数字_UVa1225周期串_UVa455子序列_UVa10340

目录 P57_习题3-1_得分_UVa1585 P57_习题3-2_分子量_UVa1586 原子数范围0~99 书上给的代码 P57_习题3-3_数数字_UVa1225 P57_习题3-4_周期串_UVa455 P59_习题3-9_子序列_UVa10340 P57_习题3-1_得分_UVa1585 给出一个由O和X组成的串(长度为1~80&a…

网络原理2 TCP协议

TCP协议 文章目录TCP协议TCP的特点TCP的基本特性确认应答机制超时重传机制丢包连接管理机制TCP建立连接---三次握手TCP断开连接---四次挥手滑动窗口机制丢包问题流量控制机制拥塞控制机制延迟应答机制捎带应答机制面向字节流问题TCP中的异常处理程序崩溃了正常关机突然断电关机…

在前端解决跨域

1、环境依赖 C:\Users\cyberzhaohyvm>node -v v14.17.3 C:\Users\cyberzhaohyvm>vue -V vue/cli 5.0.4 2、在项目所在目录,安装axios 进入项目所在目录: D:\01sourcecode\10Tutorial\08Vue\17-2022-12-28-v2\elementui-demo npm install axios …

Redis单线程为什么这么快?

Redis单线程为什么这么快? 第一章 Redis单线程为什么这么快 Redis深度剖析【第一章】Redis单线程为什么这么快?前言一、Redis为什么要使用单线程,而不是多线程?单线程的优势如果Redis使用多线程:既然多线程切换存在消…

【博学谷学习记录】大数据课程-学习第一周总结

Linux服务器 对于Linux操作系统来说,其本身是一个整体,包括Linux内核、系统库和系统程序,Linux内核是其最基础的部分,它实现了对硬件资源的管理,并且提供了使用这些硬件资源的通用接口。 自1991年发布Linux内核来&…

项目实战之旅游网(十四)项目部署-Docker

为了节约资源,在生产环境中我们更多的是使用Docker容器部署SpringBoot应用, 我们要用maven里的docker插件来生成镜像并且远程连接Docker, 开启远程docker服务: # 修改docker配置文件 vim /lib/systemd/system/docker.service 把…

简阅人体姿态估计深度学习方法-simpread-Human Pose Estimation Deep Learning Approach

What is Human Pose Estimation? Human Pose Estimation (HPE) is a way of identifying and classifying the joints in the human body Human Pose Estimation(HPR 人体姿态估计)是一个对人体关节进行识别和分类的方法。 Essentially it is a way to capture a set of co…

Good Bye 2022: 2023 is NEAR C. Koxia and Number Theory

原题链接:Problem - C - Codeforces 题意: 给定一个长度为n的数组,请问是否存在一个数 x ,使得任意两个数 与满足 。若是输出 YES ,反之输出 NO 。 思路: 我们可以发现一个规律: 规律&#…

本周大新闻|沙特PIF再投Magic Leap,周融资超5.1亿美元

本周大新闻,AR方面,OVER推出众包AR地图Map2Earn;AR房产平台homeAR推扫码看房功能;苹果智能指环专利公布,支持手势和触觉反馈。 VR方面,奇遇MIX正式发布;AjnaLens将发布新XR头显;Gen…