深入理解Java内存模型(JMM)与并发

在多线程编程中,理解Java内存模型(Java Memory Model, JMM)至关重要。JMM定义了Java程序中变量(包括实例字段、静态字段和数组元素)如何在多线程环境中交互的规则。掌握这些规则,可以帮助开发者编写出正确且高效的并发程序。

什么是Java内存模型(JMM)

Java内存模型定义了线程对内存的访问方式。JMM规范了在多线程环境中,变量的读写操作是如何被一个线程可见的,以及如何控制这些操作的顺序。JMM的主要目标是解决可见性、原子性和有序性这三个核心问题。

可见性

可见性是指当一个线程修改了变量的值,其他线程是否可以立即看到这个修改。JMM通过volatile关键字、锁(synchronized)等机制保证变量的可见性。

原子性

原子性是指某些操作是不可分割的,不能被线程间的其他操作中断。典型的原子操作包括读取和写入基本数据类型变量、获取和释放锁等。

有序性

有序性是指在多线程环境中,指令重排序不会影响程序的正确性。JMM通过happens-before原则来保证操作的有序性。

happens-before原则

happens-before的概念是在多线程编程中非常重要的,它描述了操作之间的顺序关系。以下是happens-before规则的几种情况:

  1. 程序次序规则:在一个线程内,按照代码顺序,前面的操作happens-before于后面的操作。
  2. 监视器锁规则:对一个锁的解锁happens-before于后续对这个锁的加锁。
  3. volatile变量规则:对一个volatile变量的写操作happens-before于后续对这个变量的读操作。
  4. 传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。

代码示例

为了更好地理解JMM的概念,我们来看几个代码示例。

可见性示例

下面的代码演示了volatile关键字如何保证变量的可见性。

public class VisibilityDemo {private static volatile boolean flag = false;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while (!flag) {// do nothing, just wait for the flag to be true}System.out.println("Flag is true!");});Thread t2 = new Thread(() -> {try {Thread.sleep(1000); // simulate some work} catch (InterruptedException e) {e.printStackTrace();}flag = true;System.out.println("Flag has been set to true!");});t1.start();t2.start();t1.join();t2.join();}
}

在这个示例中,flag变量被声明为volatile,这保证了当t2线程修改flag变量的值后,t1线程能够立即看到这个变化。

原子性示例

下面的代码演示了如何使用同步块来确保操作的原子性。

public class AtomicityDemo {private static int count = 0;public static synchronized void increment() {count++;}public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 0; i < 1000; i++) {increment();}});Thread t2 = new Thread(() -> {for (int i = 0; i < 1000; i++) {increment();}});t1.start();t2.start();t1.join();t2.join();System.out.println("Final count value: " + count);}
}

在这个示例中,我们使用synchronized关键字来确保increment方法的原子性,使得多个线程对count变量的操作是线程安全的。

有序性示例

下面的代码展示了如何通过synchronized块来保证操作的有序性。

public class OrderingDemo {private static boolean flag = false;private static int a = 0;public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {a = 1;flag = true;});Thread t2 = new Thread(() -> {if (flag) {System.out.println("a: " + a);}});t1.start();t2.start();t1.join();t2.join();}
}

在这个示例中,由于t1线程对flag的写操作和t2线程对flag的读操作之间没有任何同步机制,可能会导致t2线程看到flagtrue,但a的值仍然是0。这种情况可以通过使用synchronized块或volatile变量来避免。

结论

Java内存模型(JMM)是多线程编程的基础。理解可见性、原子性和有序性,以及happens-before原则,对于编写正确且高效的并发程序至关重要。通过示例代码,我们可以更直观地理解JMM的概念和使用方法。

希望这篇博客能够帮助你更好地理解Java内存模型和并发编程。如果你有任何问题或建议,请随时留言讨论。Happy coding!

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

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

相关文章

半导体制造中的压缩气体及其高压扩散器如何选择 北京中邦兴业

了解高压扩散器 高压扩散器&#xff08;HPD&#xff09;对于保持压缩气体样品中颗粒计数的精度至关重要。它们充当颗粒计数器和压缩气体管线之间的纽带&#xff0c;在气体进入颗粒计数器的样品入口时使其扩散。这确保了压力得到控制&#xff0c;以防止对颗粒计数器样品室的敏感…

uniapp学习(001 前期介绍)

零基础入门uniapp Vue3组合式API版本到咸虾米壁纸项目实战&#xff0c;开发打包微信小程序、抖音小程序、H5、安卓APP客户端等 总时长 23:40:00 共116P 此文章包含第1p-第p10的内容 简介 目录结构 效果 打包成小程序 配置开发者工具 打开安全按钮 使用uniapp的内置组件…

3DMAX一键虚线图形插件DashedShape使用方法

3DMAX一键虚线图形插件使用方法 3dMax一键虚线图形插件&#xff0c;允许从场景中拾取的样条线创建虚线形状。该工具使你能够创建完全自定义的填充图案&#xff0c;为线段设置不同的材质ID&#xff0c;并在视口中进行方便的预览。 【版本要求】 3dMax 2012 – 2025&#xff08;…

二十六、 如何确定落实数据跨境传输合规措施的内部牵头部门?

企业在落实数据跨境传输合规措施时&#xff0c;可能会需要法务、信息安全与安全运维、审计内控、人力资源等多个部门联动配合。 其中&#xff0c;法务部门通常负责协助相关部门识别在业务开展过程中涉及的各种数据类型&#xff0c;梳理各种类型数据的境内外传输链路&#xff0c…

es6 proxy的作用和用法

Proxy 是 ES6 中新增的一个构造函数&#xff0c;它用于创建一个代理对象&#xff0c;可以拦截并自定义对象的基本操作&#xff0c;例如属性查找、赋值、枚举、函数调用等。 使用 Proxy 可以实现许多高级功能&#xff0c;例如数据绑定、校验、撤销/重做等。下面是一个简单的示例…

Python 动态导入库

Python 动态导入库 从一个文件夹下遍历所有.py文件&#xff0c;并利用__Import__()函数实现全局导入 例程 import os # 导入操作系统接口模块 import sys # 导入系统模块# 将当前目录下的 DIR 目录添加到系统路径中&#xff0c;以便后续导入模块 sys.path.append(./DIR)# …

LeetCode每日一题:将元素分配到两个数组中 II - 二叉索引树BIT

大家好&#xff01;今天我们来聊聊一道有趣的LeetCode分配问题将元素分配到两个数组中 II。&#x1f4ca; 问题描述 给你一个下标从 1 开始、长度为 n 的整数数组 nums 。 现定义函数 greaterCount &#xff0c;使得 greaterCount(arr, val) 返回数组 arr 中 严格大于 val 的…

spring入门aop和ioc

文章目录 spring分层架构表现层服务层&#xff08;业务层&#xff09;持久层 spring核心ioc&#xff08;控制反转&#xff09;1)**接下来是代码示例&#xff1a;**2)**ioc容器的使用过程**3)ioc中的bean管理4)实例化bean的三种方式 aop&#xff08;面向切面开发&#xff09; 定…

数据结构与算法笔记:基础篇 - 数组:为什么数组都是从0开始编号

概述 提到数组&#xff0c;大家应该都不陌生。每一种编程语言基本都会有数组这种数据类型。不过&#xff0c;它不仅仅是一种编程语言中的数据类型&#xff0c;还是一种基础的数据结构。尽管数组看起来非常简单&#xff0c;但是我估计很多人并没有理解这个数据结构的精髓。 在…

AB测试实战

AB测试实战 1、AB测试介绍&#x1f43e; 很多网站/APP的首页都会挂一张头图(Banner)&#xff0c;用来展示重要信息&#xff0c;头图是否吸引人会对公司的营收带来重大影响&#xff0c;一家寿险公司Humana设计了如下三张头图&#xff0c;现在需要决定使用哪一张放到首页&#x…

FastDFS分布式文件系统

一、概述 FastDFS是一款由国人余庆开发的轻量级开源分布式文件系统&#xff0c;它对文件进行管理&#xff0c;功能包括&#xff1a;文件存储、文件同步、文件访问&#xff08;文件上传、文件下载&#xff09;等&#xff0c;主要解决大容量文件存储和高并发访问问题&#xff0c…

jenkins应用2-freestyle-job

1.jenkins应用 1.jenkins构建的流程 1.使用git参数化构建&#xff0c;用标签区分版本 2.git 拉取gitlab远程仓库代码 3.maven打包项目 4.sonarqube经行代码质量检测 5.自定义制作镜像发送到远程仓库harbor 6.在远程服务器上拉取代码启动容器 这个是构建的整个过程和步骤…

保姆级教程:Redis 主从复制原理及集群搭建

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

线程池的工作原理

文章目录 一、应用场景二、工作原理三、主要函数 一、应用场景 传统并发变成的缺陷&#xff1a; 1.创建和销毁线程上花费的时间和消耗的系统资源&#xff0c;甚至可能要比花在处理实际的用户请求的时间和资源要多得多 2. 活动的线程需要消耗系统资源&#xff0c;如果启动太多&…

Python基础教程教材:从入门到精通的全方位解析

Python基础教程教材&#xff1a;从入门到精通的全方位解析 Python&#xff0c;作为一门强大的编程语言&#xff0c;正日益受到全球开发者的青睐。无论是数据分析、人工智能还是Web开发&#xff0c;Python都展现出其独特的魅力。然而&#xff0c;对于初学者来说&#xff0c;如何…

新规:互联网政务应用安全管理规定将于7月1日正式执行

随着互联网技术的快速发展&#xff0c;政务服务也逐渐向数字化、智能化、便捷化转型。为了保障互联网政务应用的安全&#xff0c;保障公民信息不被泄露&#xff0c;为了让大家放心&#xff0c;我国政府出台了互联网政务应用安全管理规定。此规定将于24年7月1日正式执行。 1、规…

安卓自动化之minicap截图

安卓自动化之minicap截图 关于安卓自动化使用找图方法点击时&#xff0c;最大的痛点是使用原生adb截图速度太慢了&#xff0c;大概需要3s的时间&#xff0c;再加上我们使用opencv的找图算法&#xff0c;时间就去都三秒多了&#xff0c;为了解决这一个痛点&#xff0c;我们就可…

HBase数据库面试知识点:第二部分 - 核心技术(持续更新中)

目录 1. 分布式存储与HDFS 2. 面向列的存储 3. 数据版本控制 4. Region与RegionServer 5. 分布式协调服务&#xff08;ZooKeeper&#xff09; 1. 分布式存储与HDFS HBase利用Hadoop的HDFS作为其底层存储系统&#xff0c;确保数据的高可靠性和可扩展性。 数据块&#xff0…

Python爬虫如何入门:一步步走向精通的指南

Python爬虫如何入门&#xff1a;一步步走向精通的指南 在信息爆炸的时代&#xff0c;爬虫技术已经成为获取、整理和分析数据的必备技能。Python&#xff0c;以其简洁易懂的语法和强大的库支持&#xff0c;成为了爬虫开发的热门语言。那么&#xff0c;如何入门Python爬虫呢&…

研发质量测试工程师的笔试题

研发质量测试工程师的笔试题通常会考察候选人在测试理论、测试方法、测试工具使用以及实际案例分析等方面的知识和能力。以下是一些可能出现在研发质量测试工程师笔试中的题目类型和内容&#xff1a; 一、测试理论题 请简述软件测试的目的和基本原则。描述黑盒测试和白盒测试…