当前位置: 首页 > news >正文

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要把主内存中变量的值更新到工作内存中

关于线程可见性的控制,可以使用volatilesynchronized来实现,后面章节会有详细介绍。

有序性

有序性指的是程序按照代码的先后顺序执行。

为了性能优化,编译器和处理器会进行指令冲排序,有时候会改变程序语句的先后顺序,比如程序。

 
  1. int a = 1; //1

  2. int b = 20; //2

  3. int c = a + b; //3

编译器优化后可能变成

 
  1. int b = 20; //1

  2. int a = 1; //2

  3. 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. 指令1:分配一款内存M

  2. 指令2:在内存M上初始化Singleton对象

  3. 指令3:将M的地址赋值给instance变量

编译器优化后的操作指令:

  1. 指令1:分配一块内存S

  2. 指令2:将M的地址赋值给instance变量

  3. 指令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这就是我手机的地址&#xff0…...

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容器&#xff08;文件名是Dockerfile可以省略&#xff0…...

PDF转PowerPoint - Java实现方法

通过编程实现PDF转PPT的功能&#xff0c;可以自动化转换过程&#xff0c;减少手动操作的工作量&#xff0c;并根据需要进行批量转换。将PDF文件转换为PPT文档后&#xff0c;可以利用PPT的丰富功能和动画效果&#xff0c;达到更好的演示效果。 在Java中&#xff0c;我们可以使用…...

【Spring之手写一个依赖注入容器】

Spring之手写一个依赖注入容器 1. 创建两个自定义注解1.1 Component注解1.2 DI注解 2. ApplicationContext接口与实现类2.1 ApplicationContext 接口2.2 实现类&#xff1a;DefaultListableApplicationContext 3. 定义DAO层和Service层及其实现4. 定义异常信息类4.1 InjectBean…...

kafka之java客户端实战

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

图解渠道网关:不只是对接渠道的接口(一)

这是《百图解码支付系统设计与实现》专栏系列文章中的第&#xff08;20&#xff09;篇。点击上方关注&#xff0c;深入了解支付系统的方方面面。 主要讲清楚什么是渠道&#xff0c;有哪些类型的渠道&#xff0c;什么是渠道网关&#xff0c;渠道网关在支付系统中定位、核心功能…...

【js版数据结构学习之队列】

队列 一、简要认识队列二、队列的封装三、队列的应用1.栈和队列的转换2.全排列3.任务调度4.缓存管理 一、简要认识队列 结构&#xff1a;一种特殊的线性表 入队&#xff1a;在队尾插入一个元素 出队&#xff1a;在队头删除一个元素 特点&#xff1a;先入先出 空队列&#xff1…...

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来解决问题。提示用户输入课程数量,是否选择,并且课程代码,最后还需显示已经完成的课程注册数量或者未完成的注册…...

2026 国内 ChatGPT 镜像站推荐

&#x1f4d6; 国内直接访问&#xff0c;支持 GPTs、绘图、文件分析&#xff0c;对话数据隔离 ✅ 写方案/周报&#xff0c;描述需求直接生成&#xff0c;5分钟搞定 ✅ 代码报错&#xff0c;粘贴进去秒出解决方案 ✅ 读文件/PDF&#xff0c;上传即可提问&#xff0c;不用逐字看…...

H3CSE 高性能园区网:生成树保护机制

H3CSE 高性能园区网&#xff1a;生成树保护机制一、生成树保护机制1. BPDU保护1.1 边缘端口特点及问题端口基础特性存在的安全隐患1.2 BPDU保护机制核心防护逻辑机制运行优势1.3 BPDU保护配置配置使用规范H3C设备配置命令2. 根桥保护2.1 根桥保护机制2.2 根桥保护配置要求2.3 根…...

美股软件股反弹:AI 重塑软件未来,谁能成为时代赢家?

美股软件股遭遇“集体误杀”去年 10 月底开始&#xff0c;美股软件股经历罕见“集体误杀”。以软件 ETF——IGV 为代表&#xff0c;软件板块从高位显著回撤&#xff0c;跌幅接近 40%。曾经的高质量成长资产软件公司&#xff0c;沦为 AI 浪潮下的“旧世界遗产”。恐慌源于 DeepS…...

三分钟完成Taotoken的PythonSDK配置与首次聊天补全调用

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 三分钟完成Taotoken的Python SDK配置与首次聊天补全调用 对于刚拿到Taotoken API Key的Python开发者来说&#xff0c;最迫切的需求…...

2026毕设求生指南:用产品思维交付你的“第一份作品”

前言&#xff1a;别把毕设当作业&#xff0c;它是你职业起点的“第一份产品” 打开电脑&#xff0c;面对“毕业设计”四个字&#xff0c;你是否感到一片空白&#xff1f; 收藏了无数篇“毕设攻略”&#xff0c;却依然不知道从何下手——看文献像大海捞针&#xff0c;写代码bu…...

初创团队如何利用 Taotoken Token Plan 有效控制 AI 实验成本

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 初创团队如何利用 Taotoken Token Plan 有效控制 AI 实验成本 对于资源有限的初创团队而言&#xff0c;在产品原型和概念验证阶段&…...

Wannakey:无需支付赎金,从内存中恢复WannaCry加密文件

Wannakey&#xff1a;无需支付赎金&#xff0c;从内存中恢复WannaCry加密文件 【免费下载链接】wannakey Wannacry in-memory key recovery 项目地址: https://gitcode.com/gh_mirrors/wa/wannakey Wannakey是一款专为WannaCry勒索软件受害者设计的内存密钥恢复工具&…...

转行简历不会衔接?AI一键生成,自然过渡无违和感,邀约率飙升3倍!

“我以前是做销售的&#xff0c;想转行产品经理&#xff0c;简历上怎么写才能不让HR觉得我风马牛不相及&#xff1f;” “干了几年运营&#xff0c;现在想尝试开发&#xff0c;简历里除了写熟悉Word、Excel&#xff0c;还能写啥&#xff1f;” “裸辞转行&#xff0c;简历一片…...

云飞云 + SolidWorks服务器 = 10人研发共享方案,附硬件配置清单

10人研发团队用SolidWorks搞设计&#xff0c;是中小制造企业最常见的场景——模型要画、装配要搭、渲染要跑、图纸要存&#xff0c;每天8小时高强度运转。传统模式下每台工作站动辄2~3万元&#xff0c;10台就是25万起步&#xff1b;软件授权10套License&#xff0c;年费轻松30~…...

【设计模式 14】责任链:谁来拍板

这一课讲责任链模式。什么在变&#xff1a;处理链路经常调整&#xff0c;审批层级和条件经常变。怎么挡&#xff1a;处理者串成链&#xff0c;每个只决定"签还是传"。那张采购申请单在三个部门之间转了十七天。 十七天。买的东西是一批进口检测设备&#xff0c;总价两…...