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

CCS:Code Composer Studio 12.8.1 窗口颜色改为深色

Code Composer Studio (CCS) 基于 Eclipse 平台开发&#xff0c;要将其界面改为深色模式&#xff0c;最推荐且有效的方法是安装 Eclipse Color Theme 插件。以下是针对 CCS 12.8.1 的具体操作步骤&#xff1a;&#x1f6e0;️ 第一步&#xff1a;安装主题插件在 CCS 菜单栏中&a…...

3步解除音乐枷锁:QMCDecode全场景音频解密指南

3步解除音乐枷锁&#xff1a;QMCDecode全场景音频解密指南 【免费下载链接】QMCDecode QQ音乐QMC格式转换为普通格式(qmcflac转flac&#xff0c;qmc0,qmc3转mp3, mflac,mflac0等转flac)&#xff0c;仅支持macOS&#xff0c;可自动识别到QQ音乐下载目录&#xff0c;默认转换结果…...

从sipML5到现代框架:FreeSWITCH WebRTC客户端升级指南与选型建议

从sipML5到现代框架&#xff1a;FreeSWITCH WebRTC客户端升级指南与选型建议 如果你正在维护一个基于sipML5的FreeSWITCH WebRTC前端项目&#xff0c;可能已经感受到了技术债的压力——浏览器兼容性问题频发、功能扩展困难、社区支持几乎为零。这不是你的错&#xff0c;sipML5作…...

NaViL-9B实战手册:健康检查API与服务异常定位全流程

NaViL-9B实战手册&#xff1a;健康检查API与服务异常定位全流程 1. 平台概览 NaViL-9B是由专业AI研究机构开发的原生多模态大语言模型&#xff0c;能够同时处理纯文本问答和图片理解任务。该模型特别针对中文场景优化&#xff0c;支持中英文混合输入&#xff0c;为开发者提供…...

基于springboot框架的校园外卖管理系统的设计与实现

目录需求分析与功能规划技术选型与架构设计数据库设计与建模核心功能实现系统集成与测试部署与运维优化与扩展项目技术支持源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作需求分析与功能规划 明确校园外卖管理系统的核心需求&#xff0c;包…...

泛微OA Ecology 安全补丁管理账号配置与实战

1. 泛微OA Ecology安全补丁管理账号配置详解 第一次接触泛微OA Ecology系统的安全补丁管理功能时&#xff0c;我完全没意识到这个看似简单的配置背后藏着这么多门道。直到有次系统被恶意攻击&#xff0c;才发现默认的管理账号存在安全隐患。今天就带大家彻底搞懂这个关键配置&a…...

ESP8266-ESP32 物联网开发入门

ESP8266/ESP32物联网开发入门指南 在智能家居、远程监控和工业自动化等领域&#xff0c;物联网技术正快速改变我们的生活。作为物联网开发的热门选择&#xff0c;ESP8266和ESP32凭借低成本、高性能和丰富的开发资源&#xff0c;成为初学者和工程师的首选。本文将介绍如何快速入…...

Phi-4-Reasoning-VisionGPU算力:双卡4090推理吞吐达12 token/s实测

Phi-4-Reasoning-VisionGPU算力&#xff1a;双卡4090推理吞吐达12 token/s实测 1. 项目概述 Phi-4-Reasoning-Vision是一款基于微软Phi-4-reasoning-vision-15B多模态大模型开发的高性能推理工具。该工具专为双卡RTX 4090环境优化&#xff0c;通过精心设计的架构和优化策略&a…...

Phi-3-mini-128k-instruct辅助Dev-C++初学者:C/C++编译错误智能解读

Phi-3-mini-128k-instruct&#xff1a;你的Dev-C编程“陪练” 刚学C/C那会儿&#xff0c;你是不是也经常被Dev-C弹出的那一大串编译错误信息搞得一头雾水&#xff1f;什么“undefined reference”&#xff0c;什么“expected ‘;’ before ‘}’ token”&#xff0c;每个单词都…...

从数据包到DMA:图解GMAC传输描述符的完整生命周期(含TSO/VLAN案例)

从数据包到DMA&#xff1a;图解GMAC传输描述符的完整生命周期&#xff08;含TSO/VLAN案例&#xff09; 在网络硬件加速领域&#xff0c;GMAC&#xff08;Gigabit Media Access Control&#xff09;接口的传输描述符机制是提升数据吞吐效率的核心技术之一。本文将深入剖析一个网…...