多线程(volatile)

volatile的功能

  1. 保证内存可见性
  2. 禁止指令重排序

内存可见性

简单的理解

两(多)个线程同时针对一个变量进行操作, 一个线程读, 一个线程修改, 此时读到的值不一定是修改过后的值
即读线程没有感知到变量的变化 (其实是 编译器/JVM 对于代码在多线程情况下的优化进行了误判)

从 JMM (Java Memory Model) 角度解释 内存可见性

Java 程序里, 每个线程有自己的工作内存
t1 线程进行读取的时候, 先从主内存读取到工作内存, 再从工作内存中读取值
t2 线程进行修改的值, 先修改自己工作内存中的值, 然后把工作内存的值同步到主内存
由于编译器优化, 导致 t1 没有重新从主内存同步数据到工作内存,读到的结果就是 “修改之前” 的值

这个 “编译器优化”, 就是如果你连续10000次读取值的时候, 如果发现主内存和工作内存中的值没有任何变化, 那么在第10001次读取值的时候, 编译器就不把主内存的数据同步给工作内存了 (同步也是需要消耗资源的…), 而是直接从工作内存读取数据 (编译器默认你第10000次和第10001次的操作是一样的 …)


指令重排序

其实也是编译器优化的误判

比如一段代码中有这样的操作 (List list = new ArrayList<>() ), 可以把将该操作拆分成三个步骤

  1. 申请内存空间
  2. 调用构造方法, 将该内存空间初始化成一个合理的对象
  3. 把内存空间的地址赋值给 list 使用

如果编译器任务按你的代码逻辑 (顺序执行 1->2->3 步)比较, 并且修改代码的执行顺序 (从1->2->3 变成 1->3->2) 并不会影响最终的结果, 那么编译器就会将代码的顺序进行调整.

其实这里本质上是 研究 JVM 的大佬对我们这些菜鸟的帮助 (你写的代码如果太差, 我帮你提提速), 但是在多线程情况下, 可能会产生误判 (顺序改变后如果对代码执行结果有影响呐?), 所以说指令重排序是编译器对于代码优化的误判 … (好心办坏事)


volatile

volatile 解决内存可见性和指令重排序的问题
给变量手动加上 volatile 关键字, 就是告诉编译器, 这个变量是 “易变” 的, 每次使用的时候都要重新读取这个变量的内存内容, 不要随随便便进行优化了

问题代码

class Counter {public int count = 0;
}public class Main{public static void main(String[] args) throws InterruptedException {Counter counter = new Counter();Thread t1 = new Thread(() -> {while(counter.count == 0) ;System.out.println("counter.count 已被修改");});Thread t2 = new Thread(() -> {Scanner sc = new Scanner(System.in);System.out.println("请修改 counter.count 的值");counter.count = sc.nextInt();});t1.start();t2.start();t1.join();t2.join();}
}

运行结果

运行之后会发现, 对于 t2 线程中修改 变量 count 的值, 线程 t1 是无感知的, 体现在运行结果上就是死循环一直执行, 程序不会结束

在这里插入图片描述

解决方法

给变量 count 加上关键字 volatile

class Counter {volatile public int count = 0;
}

运行结果

运行结果, t1 线程感知到 t2 线程中变量的修改

在这里插入图片描述

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

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

相关文章

Vue3 + antv/x6 实现流程图

新建流程图 // AddDag.vue <template><div class"content-main"><div class"tool-container"><div click"undo" class"command" title"后退"><Icon icon"ant-design:undo-outlined" /…

初识Python语言-课堂练习【pyhton123题库】

初识Python语言-课堂练习【pyhton123题库】 一、单项选择题 1、Guido van Rossum正式对外发布Python版本的年份是&#xff1a; A 2008B 1998C 1991D 2002 【答案】C 【解析】暂无解析2、下面不是Python语言特点的是&#xff1a;‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪…

无需编程技能:Python爬虫与数据可视化毕业论文代写服务

引言 作为一名在软件技术领域深耕多年的专业人士,我不仅在软件开发和项目部署方面积累了丰富的实践经验,更以卓越的技术实力获得了🏅30项软件著作权证书的殊荣。这些成就不仅是对我的技术专长的肯定,也是对我的创新精神和专业承诺的认可。我的专业知识涵盖了从前端界面设…

Visual Studio 2022之Release版本程序发送到其它计算机运行

目录 1、缺少dll​ 2、应用程序无法正常启动 3、This application failed to start because no Qt platform plugin could be initialized. 代码在Debug模式下正常运行&#xff0c;然后切换到Release模式下&#xff0c;也正常运行&#xff0c;把第三方平台的dll拷贝到exe所在…

honle电源维修UV电源控制器维修EVG EPS60

好乐UV电源控制器维修&#xff1b;honle控制器维修&#xff1b;UV电源维修MUC-Steuermodul 2 LΛmpen D-82166 主要维修型号&#xff1a; EVG EPS 60/120、EVG EPS 100、EVG EPS200、EVG EPS 220、EVG EPS 340、EVG EPS40C-HMI、EVG EPS60 HONLE好乐uv电源维修故障包括&#…

React组件(函数式组件,类式组件)

函数式组件 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>React Demo</title> <!-- 引…

基于FPGA加速的bird-oid object算法实现

导语 今天继续康奈尔大学FPGA 课程ECE 5760的典型案例分享——基于FPGA加速的bird-oid object算法实现。 &#xff08;更多其他案例请参考网站&#xff1a; Final Projects ECE 5760&#xff09; 1. 项目概述 项目网址 ECE 5760 Final Project 模型说明 Bird-oid object …

镭雕机:如何利用激光技术实现高质量的产品标记

镭雕机是一种利用激光技术实现高质量产品标记的设备。它通过激光束在各种不同的物质表面进行精确的打标&#xff0c;可以产生永久性的标记效果&#xff0c;这些标记不仅精美&#xff0c;而且具有高度的精度和清晰度。以下是镭雕机如何利用激光技术实现高质量产品标记的详细过程…

寄存器(内存访问)

文章目录 寄存器&#xff08;内存访问&#xff09;1 内存中字的存储2 DS和[address]3 字的传送4 mov、add、sub指令5 数据段6 栈7 CPU提供的栈机制8 栈顶超界的问题9 push、pop指令10 栈段 寄存器&#xff08;内存访问&#xff09; 1 内存中字的存储 CPU中&#xff0c;用16位寄…

Spring Cloud Gateway如何实现熔断

Spring Cloud Gateway熔断集成 熔断应用&#xff1a; 金融市场中的熔断机制&#xff1a;在金融交易系统中&#xff0c;熔断机制&#xff08;Circuit Breaker&#xff09;是一种市场保护措施&#xff0c;旨在预防市场剧烈波动时可能导致的系统性风险。当某个基准指数&#xff08…

基于Ambari搭建大数据分析平台

一、部署工具简介 1. Hadoop生态系统 Hadoop big data ecosystem in Apache stack 2. Hadoop的发行版本 Hadoop的发行版除了Apache的开源版本之外&#xff0c;国外比较流行的还有&#xff1a;Cloudera发行版(CDH)、Hortonworks发行版&#xff08;HDP&#xff09;、MapR等&am…

【网络安全】-数字证书

数字证书 数字证书是互联网通讯中用于标志通讯各方身份信息的一串数字或数据&#xff0c;它为网络应用提供了一种验证通信实体身份的方式。具体来说&#xff0c;数字证书是由权威的证书授权&#xff08;CA&#xff09;中心签发的&#xff0c;包含公开密钥拥有者信息以及公开密…

linux中将终端Terminal添加到任务栏

问题描述 如题&#xff0c;默认的任务栏中没有终端这一组件&#xff0c;因此&#xff0c;想要打开终端&#xff0c;需要先切换到桌面&#xff0c;影响了使用体验。 解决方法 1.在applications里找到Terminal Emulator。 2.将Terminal Emulator拖动到任务栏&#xff0c;即可…

【完美实现】VITE + VUE3 + SVG图片解析+element-plus开发环境初始化(基于macos)

一、最终效果 废话少说&#xff0c;直接上效果 这是我的初始化程序提供的页面&#xff0c;在这个页面上实现了一下几个功能&#xff1a; 1、vite初始化之后的路由安装和初始化&#xff1b; 2、标准SVG的解析&#xff0c;并可调整大小、颜色&#xff1b; 3、element-plus的安…

Websocket在Asp.net webApi(.net framework)上的应用

之前在写看板部分的web api的时候&#xff0c;都是通过Ajax在规定时间内轮询调用web api&#xff0c;这样简单省事&#xff0c;但是当看板多了&#xff08;并发量上来&#xff09;以后&#xff0c;比较消耗服务器的性能&#xff0c;所以最近研究了websocket&#xff0c;希望使用…

运放的基础知识

运算放大器&#xff08;Operational Amplifier&#xff0c;简称运放&#xff09;是一种直流耦合、差模&#xff08;差动模式&#xff09;输入的高增益电压放大器&#xff0c;通常具有单端输出。它能产生一个相对于输入端电势差大数十万倍的输出电势&#xff08;对地而言&#x…

Jenkins Pipeline实现Golang项目的CI/CD

Jenkins Pipeline实现Golang项目的CI/CD 背景 最近新增了一个Golang实现的项目&#xff0c;需要接入到现有的流水线架构中。 流程图 这边流程和之前我写过的一篇《基于Jenkins实现的CI/CD方案》差不多&#xff0c;不一样的是构建现在是手动触发的&#xff0c;没有配置webho…

蓝桥杯倒计时 36天-DFS练习

文章目录 飞机降落仙境诅咒小怂爱水洼串变换 飞机降落 思路&#xff1a;贪心暴搜。 #include<bits/stdc.h>using namespace std; const int N 10; int t,n; //这题 N 比较小&#xff0c;可以用暴力搜搜复杂度是 TN*N! struct plane{int t,d,l; }p[N]; bool vis[N];//用…

OceanBase中binlog service 功能的试用

OBLogProxy简介 OBLogProxy即OceanBase的增量日志代理服务&#xff0c;它可与OceanBase建立连接并读取增量日志&#xff0c;从而为下游服务提供了变更数据捕获&#xff08;CDC&#xff09;的功能。 关于OBLogProxy的详尽介绍与具体的安装指引&#xff0c;您可以参考这篇官方OB…

RocketMQ快速入门_2. rocketmq 的应用场景、与其他mq的差异

0. 引言 之前我们讲解过rabbitMQ&#xff0c;本期我们将进入吞吐量更加强大的rocketMQ的学习。 1. 基础概念 如果你是刚接触MQ的同学&#xff0c;还不清楚消息队列的基础概念的&#xff0c;可以参考我之前这篇文章&#xff1a; https://wu55555.blog.csdn.net/article/deta…