【Java 快速复习】 Java 内存模型 并发问题本质

news2024/11/16 23:59:45

【Java 快速复习】 Java 内存模型 & 并发问题本质

在 Java 领域,我们经常会说两个名词大家要有所区分:

  1. JVM 内存模型:这个所说的是 JVM 内存的划分规则,如 堆、栈、元空间等
  2. Java 内存模型:这个所说的是线程和主内存之间,以及 CPU 高速缓存和内存之间的抽象关系,,这种抽象关系带来的就是 Java 并发问题,Java 内存模型规范了 JVM 如何提供按需禁用缓存和编译优化的方法。具体来说,这些方法包括 volatile、synchronized 和 final 三个关键字

并发问题源头

主要是三个问题:

  1. 缓存带来的可见性问题。
  2. 编译优化带来的有序性问题。
  3. 线程切换带来的原子性问题 (Java 语言分解成 CPU 指令操作并不是原子)。

可见性

多核 CPU 缓存(寄存器) 和 内存间存在可见性问题

A 线程 使用 CPU-1 读取内存中变量 X = 1 ;

B 线程 使用 CPU-2 读取内存中变量 X = 1;

A B 线程操作变量都是在本核 CPU 缓存中执行操作,最后写回。这个操作过程对于 A B 两线程是不可见的。

在这里插入图片描述

这就是可见性问题,解决该问题即,禁用 CPU 缓存,Java 中 volatile 关键字

有序性

Java 程序在编译过程中为了优化性能,有时会改变程序中语句的先后顺序

int a = 1;
int b = 2;

优化后可能为

int b = 2;
int a = 1;

这类优化调整了语句的顺序但不影响程序的最终结果。

其实我们在聊有序性的时候,最有可能遇到的问题是单例初始化时的双重检查。下面是一个比较常见的双重检查获取单例对象的代码

public class Singleton {
  static Singleton instance;
  static Singleton getInstance(){
    if (instance == null) {
      synchronized(Singleton.class) {
        if (instance == null)
          instance = new Singleton();
        }
    }
    return instance;
  }
}

这个 getInstance() 方法看上去没有什么问题,但在指令重排后就有可能引发并发问题。

我们认为的 instance 赋值过程是

  1. 划分一块内存 M
  2. 在 M 中初始化 Singleton 对象
  3. 将 M 内存地址赋值给 instance 变量

而实际指令重排后

  1. 划分一块内存 M
  2. 将 M 内存地址赋值给 instance 变量
  3. 在 M 中初始化 Singleton 对象

这会导致在第二步的时候 instance 变量就不为 null 了,但此时对象还未初始化,如果多线程调用就可能返回一个未初始化的对象,从而导致程序错误。

同样的解决该问题的方法就是禁用指令重排,在 Java 中使用 volatile 关键字

原子性

CPU 能够保证的原子操作是 CPU 指令级别的,而一个 Java 语句可能会对应多个 CPU 指令,这就导致 Java 的单个语句可能并不是原子的,在线程切换的时候就可能出现并发问题,所以需要我们在 Java 语言的级别保证某些操作的原子性。

比如执行一个 +1 的操作

int count = 0;
void addOne(){
	count++;
}

如果有多个线程同时调用 addOne() 方法,这个最终的总数是不准确的。

对于 ++ 操作拆解成 CPU 指令至少需要三条:

  1. 将 count 变量加载到 CPU 寄存器
  2. 在寄存器中执行 +1 操作
  3. 将结果写回内存

在这个流程中多个线程同时调用 addOne 方法,线程 A 读取 count 值为 0,线程 B 读取 count 值也是 0

线程 A 执行完毕写回内存 count 值为 1,线程 B 执行完毕写回内存 count 值也为 1。我们期望这个值应该为 2 。

看上去似乎是可见性的问题 volatile 关键字修饰后能否解决这个问题。

其实是不能的,volatile 能解决一部分问题,它解决不了线程切换的问题。需要通过互斥锁来解决,在 Java 中即 synchronized

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

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

相关文章

【计算机网络】应用层

应用层的许多协议都是基于客户服务器方式。 客户和服务器指通信中所涉及的两个应用进程。客户服务器方式描述的是进程之间服务和被服务的关系。客户是服务请求方,服务器是服务提供方。 P2P模式:整个网络中的传输内容不再被保存在中心服务器中&#xff…

怎么裁剪视频?手把手教你裁剪

这两年,随着网课的不断发展,我们可以很轻松的就在网上找到各种课程视频。可是有时候,一些视频里面的重点内容往往只有那几分钟,当我们回顾的时候,需要不断跳转,这就显得有些麻烦。其实我们可以将重点内容裁…

【代码随想录】二刷-回溯算法

回溯算法 《代码随想录》 什么是回溯算法? 回溯算法也可以叫做回溯搜索法,它是一种搜索方式。回溯是递归的副产品,只要有递归就会有回溯。 回溯法的效率: 回溯法的本质是穷举,穷举所有可能,然后选出我们想要的答案。(n…

如何使用virtualenv实现python环境的隔离?

有关更多的Python 开发内容,可访问:《 Python Flask开发指南》​​​​​​​ virtualenv可以帮助我们来创建一个Python的虚拟环境,虚拟环境可以独立并隔离外部的python环境,方便我们对于不同项目使用不同的python依赖,已经依赖版本的不同而导致的错误。本篇文章主要来了解…

2022全年度冰箱十大热门品牌销量榜单

自2022年年初以来,各地纷纷部署支持包括冰箱在内的家电大宗消费政策措施,其中家电补贴政策是刺激家电消费的主旋律。宏观经济政策环境改善,利好冰箱行业的长期发展。 根据鲸参谋数据统计,今年京东平台冰箱的年度累计销量达到1400多…

论文阅读笔记《Learning Combinatorial Solver for Graph Matching》

核心思想 本文提出一种基于学习的组合求解器来实现图匹配。之前基于学习的图匹配方法都是利用神经网络提取特征构建关联矩阵,然后再利用可微分的Sinkhorn算法求解匹配矩阵。但本文提出的方法没有显式的构建关联矩阵和求解匹配矩阵的过程,而是将其转化成关…

SpringBoot:核心模块盘点

spring-boot-project 是 spring-boot 核心技术包,其中包含了 spring-boot 所有基础源码,其中很多模块都是我们了解 spring-boot 的重点。 ~ 本篇内容包括:spring-boot-project 包介绍、Spring Boot 核心模块 文章目录一、spring-b…

SpringCloud-Geteway之限流,熔断(超详细篇)

目录 一,Sentinel--服务容错 1.1 高并发带来的问题 1. 使用压测工具,对请求进行压力测试 2.修改配置文件中tomcat的并发数 1.2 服务雪崩效应 1.3 常见容错方案 1.4 Sentinel入门 什么是Sentinel 微服务集成Sentinel 安装Sentinel控制台 实现一个接口的限…

QTextLine、QGlyphRun、QTextLayout

QGlyphRun 一、描述 此类提供对字体中内部字形的直接访问。在某些情况下,开发人员可以对特定字体中的字形绘制到屏幕上进行更低级的控制。 当Qt显示以Unicode编码的文本字符串时,它会将Unicode点转换为基于字体的字形索引列表和位置列表。QGlyphRun 提…

企业对于源代码加密需求分析

需求 随着企业信息化发展的日益增长,软件行业厂商之间的竞争也愈加白热化,加上国内对知识产权的不够重视、山寨模仿产品的横行。保护源代码、保证企业的核心竞争力,成为众多软件研发企业的第一要务。那么企业应该如何保证源代码的安全呢&…

[附源码]计算机毕业设计常见Web漏洞对应PC应用系统Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

HTTP缓存机制(Cache-Control)

文章目录HTTP缓存机制HTTP缓存机制 HTTP 协议通常应用于分布式信息系统,所谓分布式信息系统,是指以计算机网络为基础,将系统的数据与功能分别布置在不同的地方,然后再通过网络将数据与功能连接的信息系统。由于系统需要处理大量的…

世界杯期间我使用Python生成二维码“为中国队辟谣”

二维码介绍 二维码本质上,就是一段字符串,我们可以把任意字符串,制作成一个二维码图片。在生活中,使用二维码更多的是一个URL(网址)。 引入 qrcode库 qrocde库网址:qrcode PyPI 进入网址之后…

[附源码]计算机毕业设计贷款申请审核管理系统论文Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

本地字节序与网络字节序的相互转换(IP地址、端口号)

一般数据在内存中是按照字节存储的,存储的方式分为大端和小端。在不知道对方主机的存储方式的情况下,我们不知道是否需要转换数据的存储方式。因此,TCP/IP协议规定:发送到网络的数据流应采用大端字节序! 如果当前主机…

年产3000吨原味奶糖生产车间工艺设计

目 录 摘 要 I Abstract II 1绪论 1 1.1原味奶糖的概念及其功能特性 1 1.2国外原味奶糖的现状 3 1.3我国的原味奶糖现状及开发前景 4 1.4原味奶糖原料的生产情况 4 2工艺流程设计 6 2.1 原味奶糖的生产工艺 6 2.1.1 溶糖与混合 7 2.1.2 连续真空薄膜熬糖 7 2.1.3 混合 8 2.1.4 …

阿里国际站-唤端技术的探索与演进

作者:黄昭 阿里ICBU买家增长技术团队 近几年用户增长领域APP推广发展迅猛,而唤端就是其中的重要技术。通过唤端拉新/促活不仅能能够将三方流量规模做大,同时二方流量也能有效利用,给网站不断带来商机,本文将为大家详细…

UE4虚幻引擎关于事件分发器的使用!

UE4虚幻引擎关于事件分发器的使用! 首先,这次就讲一下,事件分发器,在UI,Pawn,子actor如何进行事件传递! 首先!我们如果要使用事件分发器的原因是什么! 第一&#xff0…

Django(11):后台管理系统

目录后台管理系统基本操作管理平台的基本操作数据模型的注册和管理数据模型管理后台管理系统操作Xadmin管理平台Django内置了自己的后台管理系统,包含数据库管理和良好的界面。后台管理系统基本操作 在我们前面创建Django项目时,默认会有许多应用组件&a…

一次nginx “time out”故障排查

研发请求协助排查一个nginx故障。 描述如下: 在内部环境测试没问题。 打包到生产环境后,访问nginx接口地址超时。 研发比对后怀疑是nginx版本不一致导致。内部版本1.23.2,生产环境1.23.1. 收到信息第一感觉不是nginx的问题。不过先测试一…