java高并发系列 - 第4天:JMM相关的一些概念
JMM(java内存模型),由于并发程序要比串行程序复杂很多,其中一个重要原因是并发程序中数据访问一致性和安全性将会受到严重挑战。如何保证一个线程可以看到正确的数据呢?这个问题看起来很白痴。对于串行程序来说,根本就是小菜一碟,如果你读取一个变量,这个变量的值是1,那么你读取到的一定是1,就是这么简单的问题在并行程序中居然变得复杂起来。事实上,如果不加控制地任由线程胡乱并行,即使原本是1的数值,你也可能读到2。因此我们需要在深入了解并行机制的前提下,再定义一种规则,保证多个线程间可以有小弟,正确地协同工作。而JMM也就是为此而生的。
JMM关键技术点都是围绕着多线程的原子性、可见性、有序性来建立的。我们需要先了解这些概念。
原子性
原子性是指操作是不可分的,要么全部一起执行,要么不执行。在java中,其表现在对于共享变量的某些操作,是不可分的,必须连续的完成。比如a++,对于共享变量a的操作,实际上会执行3个步骤:
1.读取变量a的值,假如a=1
2.a的值+1,为2
3.将2值赋值给变量a,此时a的值应该为2
这三个操作中任意一个操作,a的值如果被其他线程篡改了,那么都会出现我们不希望出现的结果。所以必须保证这3个操作是原子性的,在操作a++的过程中,其他线程不会改变a的值,如果在上面的过程中出现其他线程修改了a的值,在满足原子性的原则下,上面的操作应该失败。
java中实现原子操作的方法大致有2种:锁机制、无锁CAS机制,后面的章节中会有介绍。
可见性
可见性是值一个线程对共享变量的修改,对于另一个线程来说是否是可以看到的。有些同学会说修改同一个变量,那肯定是可以看到的,难道线程眼盲了?
为什么会出现这种问题呢?
看一下java线程内存模型:
-
我们定义的所有变量都储存在
主内存
中 -
每个线程都有自己
独立的工作内存
,里面保存该线程使用到的变量的副本(主内存中该变量的一份拷贝) -
线程对共享变量所有的操作都必须在自己的工作内存中进行,不能直接从主内存中读写(不能越级)
-
不同线程之间也无法直接访问其他线程的工作内存中的变量,线程间变量值的传递需要通过主内存来进行。(同级不能相互访问)
线程需要修改一个共享变量X,需要先把X从主内存复制一份到线程的工作内存,在自己的工作内存中修改完毕之后,再从工作内存中回写到主内存。如果线程对变量的操作没有刷写回主内存的话,仅仅改变了自己的工作内存的变量的副本,那么对于其他线程来说是不可见的。而如果另一个变量没有读取主内存中的新的值,而是使用旧的值的话,同样的也可以列为不可见。
共享变量可见性的实现原理:
线程A对共享变量的修改要被线程B及时看到的话,需要进过以下步骤:
1.线程A在自己的工作内存中修改变量之后,需要将变量的值刷新到主内存中 2.线程B要把主内存中变量的值更新到工作内存中
关于线程可见性的控制,可以使用volatile、synchronized、锁来实现,后面章节会有详细介绍。
有序性
有序性指的是程序按照代码的先后顺序执行。
为了性能优化,编译器和处理器会进行指令冲排序,有时候会改变程序语句的先后顺序,比如程序。
-
int a = 1; //1
-
int b = 20; //2
-
int c = a + b; //3
编译器优化后可能变成
-
int b = 20; //1
-
int a = 1; //2
-
int c = a + b; //3
上面这个例子中,编译器调整了语句的顺序,但是不影响程序的最终结果。
在单例模式的实现上有一种双重检验锁定的方式,代码如下:
public class Singleton {static Singleton instance;static Singleton getInstance(){if (instance == null) {synchronized(Singleton.class) {if (instance == null)instance = new Singleton();}}return instance;}}
我们先看 instance=newSingleton();
未被编译器优化的操作:
-
指令1:分配一款内存M
-
指令2:在内存M上初始化Singleton对象
-
指令3:将M的地址赋值给instance变量
编译器优化后的操作指令:
-
指令1:分配一块内存S
-
指令2:将M的地址赋值给instance变量
-
指令3:在内存M上初始化Singleton对象
现在有2个线程,刚好执行的代码被编译器优化过,过程如下:
最终线程B获取的instance是没有初始化的,此时去使用instance可能会产生一些意想不到的错误。
现在比较好的做法就是采用静态内部内的方式实现:
public class SingletonDemo {private SingletonDemo() {}private static class SingletonDemoHandler{private static SingletonDemo instance = new SingletonDemo();}public static SingletonDemo getInstance() {return SingletonDemoHandler.instance;}}
相关文章:

java高并发系列 - 第4天:JMM相关的一些概念
JMM(java内存模型),由于并发程序要比串行程序复杂很多,其中一个重要原因是并发程序中数据访问一致性和安全性将会受到严重挑战。如何保证一个线程可以看到正确的数据呢?这个问题看起来很白痴。对于串行程序来说,根本就是小菜一碟&…...

如何卸载旧版docker
环境: Docker1.13 centos7.6 问题描述: 如何卸载旧版docker 解决方案: 1.停止Docker服务。使用以下命令停止Docker服务: sudo service docker stop2.卸载Docker软件包。根据您的Linux发行版,使用适当的包管理器来…...

Wheeltec小车的开发实录(0)
配置静态ip(可以联网) 首先在你正常链接网络的时候打开“Connection Information”(我的是wifi,而且是手机热点,所以我手机就相当于一台路由器) 查看路由ip 观察到Default Route 是192.168.***.225这就是我手机的地址࿰…...

uniapp中uview组件库的NoticeBar 滚动通知 使用方法
目录 #平台差异说明 #基本使用 #配置主题 #配置图标 #配置滚动速度 #控制滚动的开始和暂停 #事件回调 #API #Props #Events 该组件用于滚动通告场景,有多种模式可供选择 #平台差异说明 AppH5微信小程序支付宝小程序百度小程序头条小程序QQ小程序√√√√…...

蓝桥杯每日一题----货物摆放
题目 分析 上来一看,三个for循环,从1到n,寻找满足lwhn的个数,但是这样根本跑不出来答案,n太大了,1e15的级别,O(n)的时间复杂度都不行,更何况是O(…...

(二十)Flask之上下文管理第一篇(粗糙缕一遍源码)
每篇前言: 🏆🏆作者介绍:【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领域博主、CSDN原力计划作者 🔥🔥本文已收录于Flask框架从入门到实战专栏:《Flask框架从入…...

Tensorflow2.0笔记 - 基础数学运算
本笔记主要记录基于元素操作的,-,*,/,//,%,**,log,exp等运算,矩阵乘法运算,多维tensor乘法相关运算 import tensorflow as tf import numpy as nptf.__version__#element-wise运算,对应元素的,-,*,/,**,//,% tensor1 tf.fill([3,3], 4) ten…...

年底聚餐无压力,HUAWEI WATCH GT 4 助力体形管理和健康守护
过了腊八就是年,逢年过节聚餐频繁。在品味美食、享受亲情温馨的同时,你是否也在担心自己的健康与体形呢?华为WATCH GT 4搭载心率监测、血氧检测和减脂塑形等功能,让你尽情享受美食的同时保持健康。 华为WATCH GT 4的心率监测功能…...
Tomcat Notes: URL Mapping
This is a personal study notes of Apache Tomcat. Below are main reference material. - YouTube Apache Tomcat Full Tutorial,owed by Alpha Brains Courses. https://www.youtube.com/watch?vrElJIPRw5iM&t801s 1、URL Mapping To Resources1.1、What w…...

【JVM】JVM概述
JVM概述 基本介绍 JVM:全称 Java Virtual Machine,即 Java 虚拟机,一种规范,本身是一个虚拟计算机,直接和操作系统进行交互,与硬件不直接交互,而操作系统可以帮我们完成和硬件进行交互的工作特…...
【2023开发组二等奖】湖南省国土空间规划双评价系统
作品介绍 1 需求分析 1.1 背景与意义 在我国辽阔的国土空间中,各地区的地形地势、自然条件和资源环境禀赋存在显著差异。然而,随着人口增长和城市化进程加快,高强度的不合理开发和产业布局广泛分布,使得部分地区的经济社会发展规模超过了资源环境的承载能力。因此,执行主…...

Flutter为什么不需要子线程——Dart IO源码剖析(上)
Dart IO 源码剖析 许多Flutter新手,特别是安卓、iOS原生开发转做Flutter的小伙伴,一直对Flutter 单线程模型开发APP倍感不解,他们总是喜欢本能的把网络请求、文件读写放到一个单独线程去做,因为“耗时操作会阻塞UI线程嘛”。于是…...
docker使用Dockerfile制做容器(以hyperf为列,开机启动)
1、Dockerfile文件 FROM hyperf/hyperf:8.1-alpine-v3.18-swoole WORKDIR /data MAINTAINER dade <dadeqq.com> ADD start.sh start.sh RUN chmod x ./start.sh CMD /data/start.sh1-1、执行命令生成hyperf:latest容器(文件名是Dockerfile可以省略࿰…...

PDF转PowerPoint - Java实现方法
通过编程实现PDF转PPT的功能,可以自动化转换过程,减少手动操作的工作量,并根据需要进行批量转换。将PDF文件转换为PPT文档后,可以利用PPT的丰富功能和动画效果,达到更好的演示效果。 在Java中,我们可以使用…...
【Spring之手写一个依赖注入容器】
Spring之手写一个依赖注入容器 1. 创建两个自定义注解1.1 Component注解1.2 DI注解 2. ApplicationContext接口与实现类2.1 ApplicationContext 接口2.2 实现类:DefaultListableApplicationContext 3. 定义DAO层和Service层及其实现4. 定义异常信息类4.1 InjectBean…...

kafka之java客户端实战
1. kafka的客户端 Kafka提供了两套客户端API,HighLevel API和LowLevel API。 HighLevel API封装了kafka的运行细节,使用起来比较简单,是企业开发过程中最常用的客户端API。 而LowLevel API则需要客户端自己管理Kafka的运行细节,Pa…...

图解渠道网关:不只是对接渠道的接口(一)
这是《百图解码支付系统设计与实现》专栏系列文章中的第(20)篇。点击上方关注,深入了解支付系统的方方面面。 主要讲清楚什么是渠道,有哪些类型的渠道,什么是渠道网关,渠道网关在支付系统中定位、核心功能…...

【js版数据结构学习之队列】
队列 一、简要认识队列二、队列的封装三、队列的应用1.栈和队列的转换2.全排列3.任务调度4.缓存管理 一、简要认识队列 结构:一种特殊的线性表 入队:在队尾插入一个元素 出队:在队头删除一个元素 特点:先入先出 空队列࿱…...
iOS Xcode 升级Xcode15报错: SDK does not contain ‘libarclite‘
iOS Xcode 升级Xcode15报错: SDK does not contain libarclite 一、仔细查看报错代码: SDK does not contain libarclite at the path /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/ lib/arc/libarclite_iphonesimulator.a; try in…...

python高级练习题库实验2(B)部分
文章目录 题目1代码实验结果题目2代码实验结果题目总结题目1 注册课程小游戏程序 研究下面的例子,并编写一个与这些例子完全相同的程序。使用for loop和break来解决问题。提示用户输入课程数量,是否选择,并且课程代码,最后还需显示已经完成的课程注册数量或者未完成的注册…...

【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...

html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...

AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

【Linux】Linux 系统默认的目录及作用说明
博主介绍:✌全网粉丝23W,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...
C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...
Vite中定义@软链接
在webpack中可以直接通过符号表示src路径,但是vite中默认不可以。 如何实现: vite中提供了resolve.alias:通过别名在指向一个具体的路径 在vite.config.js中 import { join } from pathexport default defineConfig({plugins: [vue()],//…...

给网站添加live2d看板娘
给网站添加live2d看板娘 参考文献: stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下,文章也主…...