volatile关键字(juc编程)

volatile关键字

3.1 看程序说结果

分析如下程序,说出在控制台的输出结果。

Thread的子类

public class VolatileThread extends Thread {// 定义成员变量private boolean flag = false ;public boolean isFlag() { return flag;}@Overridepublic void run() {// 线程休眠1秒try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 将flag的值更改为truethis.flag = true ;System.out.println("flag=" + flag);}
}

测试类

public class VolatileThreadDemo01 {public static void main(String[] args) {// 创建VolatileThread线程对象VolatileThread volatileThread = new VolatileThread() ;volatileThread.start();// 在main线程中获取开启的线程中flag的值while(true) {System.out.println("main线程中获取开启的线程中flag的值为" + volatileThread.isFlag());}}
}

控制台输出结果

前面是false,过了一段时间之后就变成了true

按照我们的分析,当我们把volatileThread线程启动起来以后,那么volatileThread线程开始执行。在volatileThread线程的run方法中,线程休眠1s,休眠一秒以后那么flag的值应该为

true,此时我们在主线程中不停的获取flag的值。发现前面释放false,后面是true

信息,那么这是为什么呢?要想知道原因,那么我们就需要学习一下JMM。

3.2 JMM

概述:JMM(Java Memory Model)Java内存模型,是java虚拟机规范中所定义的一种内存模型。

Java内存模型(Java Memory Model)描述了Java程序中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这样的底层细节。

特点:

  1. 所有的共享变量都存储于主内存(计算机的RAM)这里所说的变量指的是实例变量和类变量。不包含局部变量,因为局部变量是线程私有的,因此不存在竞争问题。

  2. 每一个线程还存在自己的工作内存,线程的工作内存,保留了被线程使用的变量的工作副本。

  3. 线程对变量的所有的操作(读,写)都必须在工作内存中完成,而不能直接读写主内存中的变量,不同线程之间也不能直接访问对方工作内存中的变量,线程间变量的值的传递需要通过主

    内存完成。

在这里插入图片描述

3.3 问题分析

了解了一下JMM,那么接下来我们就来分析一下上述程序产生问题的原因。

在这里插入图片描述

产生问题的流程分析:

  1. VolatileThread线程从主内存读取到数据放入其对应的工作内存

  2. 将flag的值更改为true,但是这个时候flag的值还没有回写主内存

  3. 此时main线程读取到了flag的值并将其放入到自己的工作内存中,此时flag的值为false

  4. VolatileThread线程将flag的值写回到主内存,但是main函数里面的while(true)调用的是系统比较底层的代码,速度快,快到没有时间再去读取主内存中的值,所以while(true)

    读取到的值一直是false。(如果有一个时刻main线程从主内存中读取到了flag的最新值,那么if语句就可以执行,main线程何时从主内存中读取最新的值,我们无法控制)

我们可以让主线程执行慢一点,执行慢一点以后,在某一个时刻,可能就会读取到主内存中最新的flag的值,那么if语句就可以进行执行。

测试类

public class VolatileThreadDemo02 {public static void main(String[] args) throws InterruptedException {// 创建VolatileThread线程对象VolatileThread volatileThread = new VolatileThread() ;volatileThread.start();// main方法while(true) {if(volatileThread.isFlag()) {System.out.println("执行了======");}// 让线程休眠100毫秒TimeUnit.MILLISECONDS.sleep(100);}}
}

控制台输出结果

flag=true
执行了======
执行了======
执行了======
....

此时我们可以看到if语句已经执行了。当然我们在真实开发中可能不能使用这种方式来处理这个问题,那么这个问题应该怎么处理呢?我们就需要学习下一小节的内容。

3.4 问题处理

3.4.1 加锁

第一种处理方案,我们可以通过加锁的方式进行处理。

测试类

public class VolatileThreadDemo03 {public static void main(String[] args) throws InterruptedException {// 创建VolatileThread线程对象VolatileThread volatileThread = new VolatileThread() ;volatileThread.start();// main方法while(true) {// 加锁进行问题处理synchronized (volatileThread) {if(volatileThread.isFlag()) {System.out.println("执行了======");}}}}
}

控制台输出结果

flag=true
执行了======
执行了======
执行了======
....

工作原理说明

对上述代码加锁完毕以后,某一个线程支持该程序的过程如下:

a.线程获得锁

b.清空工作内存

c.从主内存拷贝共享变量最新的值到工作内存成为副本

d.执行代码

e.将修改后的副本的值刷新回主内存中

f.线程释放锁

3.4.2 volatile关键字

第二种处理方案,我们可以通过volatile关键字来修饰flag变量。

线程类

public class VolatileThread extends Thread {// 定义成员变量private volatile boolean flag = false ;public boolean isFlag() { return flag;}@Overridepublic void run() {// 线程休眠1秒try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 将flag的值更改为truethis.flag = true ;System.out.println("flag=" + flag);}
}
//--------------------------------更新之后的案例-------------------------------------------
public class VolatileTest extends Thread{boolean flag = false;int i = 0;public void run() {while (!flag) {i++;}System.out.println("stope" + i);}public static void main(String[] args) throws Exception {VolatileTest vt = new VolatileTest();vt.start();Thread.sleep(10);vt.flag = true;}
}

控制台输出结果

flag=true
执行了======
执行了======
执行了======
....

工作原理说明

在这里插入图片描述

执行流程分析

  1. VolatileThread线程从主内存读取到数据放入其对应的工作内存
  2. 将flag的值更改为true,但是这个时候flag的值还没有回写主内存
  3. 此时main线程读取到了flag的值并将其放入到自己的工作内存中,此时flag的值为false
  4. VolatileThread线程将flag的值写到主内存
  5. main线程工作内存中的flag变量副本失效
  6. main线程再次使用flag时,main线程会从主内存读取最新的值,放入到工作内存中,然后在进行使用

总结: volatile保证不同线程对共享变量操作的可见性,也就是说一个线程修改了volatile修饰的变量,当修改写回主内存时,另外一个线程立即看到最新的值。

​ 但是volatile不保证原子性(关于原子性问题,我们在下面的小节中会介绍)。

volatile与synchronized的区别:

  1. volatile只能修饰实例变量和类变量,而synchronized可以修饰方法,以及代码块。

  2. volatile保证数据的可见性,但是不保证原子性(多线程进行写操作,不保证线程安全);而synchronized是一种排他(互斥)的机制(因此有时我们也将synchronized这种锁称

    之为排他(互斥)锁),synchronized修饰的代码块,被修饰的代码块称之为同步代码块,无法被中断可以保证原子性,也可以间接的保证可见性。

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

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

相关文章

灵感互娱U3D笔试题

文章目录 题目1解析 题目2解析 题目3解析 题目4数组链表 题目5解析 题目6解析 题目7解析题目8解析 后话 题目1 以下C#代码的输出顺序是什么 namespace ConsoleApp2 {internal class Program{class A{ public A(string text){Console.WriteLine(text);}}class B{static A a1 …

原子性(juc编程)

原子性 概述:所谓的原子性是指在一次操作或者多次操作中,要么所有的操作全部都得到了执行并且不会受到任何因素的干扰而中断,要么所有的操作都不执行,多个操作是一个不可以分割的整体。 //比如说:你喂你女朋友吃冰淇…

ScheduledExecutorService引起的线上问题(抛出异常后不继续执行)

线上有一个服务,采用ScheduledExecutorService定时任务刷新数据库数据到本地缓存作为路由信息 private ScheduledExecutorService scheduledExecutorService Executors.newScheduledThreadPool(1);scheduledExecutorService.scheduleWithFixedDelay(new Runnable()…

【docker】adoptopenjdk/openjdk8-openj9:alpine-slim了解

adoptopenjdk/openjdk8-openj9:alpine-slim 是一个 Docker 镜像的标签,它指的是一个特定的软件包,用于在容器化环境中运行 Java 应用程序。 镜像相关的网站和资源: AdoptOpenJDK 官方网站 - AdoptOpenJDK 这是 AdoptOpenJDK 项目的官方网站&…

Nginx Rewrite技术

一:理解地址重写 与 地址转发的含义。二:理解 Rewrite指令 使用三:理解if指令四:理解防盗链及nginx配置 简介:Rewrite是Nginx服务器提供的一个重要的功能,它可以实现URL重定向功能。 一:理解地…

数据库异常恢复2-备份文件恢复(快速恢复的手动启动方式)

(四) 备份文件备份恢复的概念 本次所说的数据恢复有异于数据的导入导出 1. 备份工具 gbase8s数据库提供了两种工具进行完成系统物理备份、逻辑日志备份和系统恢复:ontape和onbar ontape:提供了基本的系统物理备份、日志备份和恢复能力,其…

C++基础知识——命名空间

P. S.:以下代码均在VS2019环境下测试,不代表所有编译器均可通过。 P. S.:测试代码均未展示头文件stdio.h的声明,使用时请自行添加。 博主主页:Yan. yan. 文章目录 1、什么是命名空间2、命名空间的作用3、如何定义命名…

js实现canvas截图功能

关键代码 使用canvas的导出功能和drawImage函数 class CropShape{cropShape(shape){let {x,y,w,h} shapeconsole.log(x,y,w,h)const roiCanvas document.createElement(canvas);document.getElementById(app).append(roiCanvas)const roiCtx roiCanvas.getContext(2d);roi…

贝叶斯优化、高斯过程相关概念总结

目录 贝叶斯优化 高斯过程 采集函数 贝叶斯优化 贝叶斯优化 &#xff5c; 黑盒优化全局最优方法 &#xff5c; Bayesian Optimization_哔哩哔哩_bilibili 贝叶斯优化用于解决寻找某个函数的最大值/最小值&#xff0c;在自变量维度比较小时(<20)表现的非常好。 适用…

《计算机英语》Unit1 计算机概述

期末试卷组成 1、选择20道 2、判断20道 3、词汇翻译&#xff08;单词词组&#xff0c;参照课后习题&#xff09; 4、翻译2道&#xff08;一道原题&#xff0c;参照作业&#xff09; Unit One Computer Overview 单元1 计算机概述 algorithm n. 算法 operate …

byte[]转MultipartFile、byte[]转File一次看个够

目录 需求背景 当你需要将byte[]、MultipartFile、File实现互转时&#xff0c;无外乎以下场景&#xff1a; 保存第三方接口返回二进制流前/后端文件流上传微服务间调用文件格式转换 正如你所需要的&#xff0c;通过搜索引擎筛选到我的本篇文章是因为你在开发中需要将byte[]转…

k8s学习笔记(一)

configMap 一般用来存储配置信息 创建configMap 从文件中获取信息创建&#xff1a;kubectl create configmap my-config --from-file/tmp/k8s/user.txt 直接指定信息&#xff1a; kubectl create configmap my-config01 --from-literalkey1config1 --from-literalkey2confi…

深度学习之计算机视觉

神经网络简介 全连接层和卷积层的根本区别在于权重在中间层中彼此连接的方式。图5.1描述了全连接层或线性层是如何工作的。 在计算机视觉中使用线性层或全连接层的最大挑战之一是它们丢失了所有空间信息&#xff0c;并且就全连接层使用的权重数量而言复杂度太高。例如&#xf…

鸿蒙Harmony实战—通过登录Demo了解ArkTS

ArkTS是HarmonyOS优选的主力应用开发语言。ArkTS围绕应用开发在TypeScript&#xff08;简称TS&#xff09;生态基础上做了进一步扩展&#xff0c;继承了TS的所有特性&#xff0c;是TS的超集。 ArkTS在TS的基础上主要扩展了如下能力&#xff1a; 基本语法&#xff1a;ArkTS定义…

最新版Cisco Packet Tracer思科模拟器Windows版本64位下载

Cisco Packet Tracer是思科公司推出的一款网络仿真工具&#xff0c;主要用于网络教学、培训和实验。它提供了一个真实的网络环境模拟平台&#xff0c;让用户可以设计、构建和调试网络&#xff0c;以及进行实时互动&#xff0c;从而帮助用户理解和实践网络技术。 通过 Cisco Pa…

Unity和UE免费领恐怖书本头怪兽角色模型恐怖或奇幻游戏monster适合FPS类型PBR202406202143

Unity和UE免费领恐怖书本头怪兽角色模型恐怖或奇幻游戏monster适合FPS类型PBR202406202143 Unity恐怖书本头怪兽角色模型&#xff1a;https://prf.hn/l/zpBqgVl UE恐怖书本头怪兽角色模型&#xff1a;https://prf.hn/l/4PzY1Qy 作者其他资产&#xff1a;https://prf.hn/l/0…

Fastjson漏洞之CVE-2022-25845

前言&#xff1a; 针对Fastjson之前已经介绍了&#xff0c;这里就不再重复了&#xff0c;漏洞CVE-2017-18349只能用来攻击>1.2.24版本的&#xff0c;CVE-2022-25845属于CVE-2017-18349的升级版&#xff0c;但是目前仅影响到1.2.83以下版本。CVE-2022-25845本质上是绕过了名…

SpringBoot | 实现邮件发送

运行环境&#xff1a; IntelliJ IDEA 2022.2.5 (Ultimate Edition) (注意&#xff1a;idea必须在2021版本以上&#xff09;JDK17 项目目录&#xff1a; 该项目分为pojo,service,controller,utils四个部分&#xff0c; 在pojo层里面写实体内容&#xff08;发邮件需要的发件人邮…

【etcd】etcd单机安装及简单操作

https://blog.csdn.net/Mr_XiMu/article/details/125026635 https://blog.csdn.net/m0_73192864/article/details/136509244 etcd在生产环境中一般为集群方式部署 etcd使用的2个默认端口号&#xff1a;2379和2380 2379&#xff1a;用于客户端通信(类似于sqlserver的1433&#x…

vscode卡顿问题处理(vue-official插件)

vue官方扩展由volar升级为vue-official&#xff0c;部分人的ide会变得非常卡顿&#xff0c;这是由于vscode本身一些问题导致&#xff0c;如下图作者解释&#xff1a; 解决方式&#xff1a; 通过禁用Hybrid模式&#xff0c;不使用tsserver来接管语言支持&#xff0c;卡顿会缓解…