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

并发编程之三大特性及JMM内存模型

目录

原子性

如何保证原子性

可见性

如何保证可见性

有序性

如何保证有序性

Java内存模型(JMM内存模型)

Java内存模型的一些关键概念:

主内存与工作内存交互协议

Java内存模型通过以下手段来确保多线程程序的正确性:

锁机制

volatile

volatile禁止指令重排序

 Happens-Before


并发三大特性

原子性、可见性、有序性

原子性

        原子性是指一个操作是不可中断的。一个原子操作是一个不可分割的整体,要么全部执行成功,要么全部不执行。在多线程环境下,当多个线程访问共享变量时,如果其中一个线程在执行某个操作,其他线程不能同时执行该操作。

public class AtomicTest {private static volatile int counter = 0;public static void main(String[] args) {for (int i = 0; i < 10; i++) {Thread thread = new Thread(() -> {for (int j = 0; j < 10000; j++) {//synchronized (AtomicTest.class) {counter++;// }}});thread.start();}try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(counter);}
}

        正常执行后counter变量的值远远大于预期10000,加synchronized后counter变量为10000

如何保证原子性

      1. 通过synchronized关键字保证原子性

      2. 通过 Lock锁保证原子性

      3. 通过 CAS保证原子性


可见性

       可见性是指当一个线程修改了共享变量的值时,其他线程能够立即看到这个修改。在多线程环境下,由于线程之间的缓存机制,一个线程对共享变量的修改可能不会立即被其他线程看到。

 

public class VisibilityExample {private static boolean stop = false;public static void main(String[] args) {// 线程1:修改共享变量Thread thread1 = new Thread(() -> {while (!stop) {// do something}System.out.println("Thread 1 finished");});// 线程2:修改共享变量Thread thread2 = new Thread(() -> {stop = true;System.out.println("Thread 2 set stop to true");});// 启动线程1thread1.start();// 稍等片刻try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}// 启动线程2thread2.start();}
}

       在以上代码中,两个线程分别运行,并且共享一个stop变量。线程1在一个循环中检查stop变量是否为false,而线程2在启动后将stop变量设置为true。然而,由于没有同步机制,线程1可能不会立即看到线程2对stop变量的修改,导致线程1一直在循环中无法退出。

private static volatile boolean stop = false;

通过给stop变量增加volatile修饰,即可保证可见性。

如何保证可见性

       通过volatile 关键字保证可见性
       通过内存屏障保证可见性
       通过synchronized 关键字保证可见性
       通过Lock锁保证可见性


有序性

       有序性是指程序执行的顺序按照代码的先后顺序执行。在多线程环境下,由于指令重排序等优化,有时候线程执行的顺序可能与代码的顺序不一致。

public class ReOrderTest {private static  int x = 0, y = 0;private  static  int a = 0, b = 0;public static void main(String[] args) throws InterruptedException {int i=0;while (true) {i++;x = 0;y = 0;a = 0;b = 0;Thread thread1 = new Thread(new Runnable() {@Overridepublic void run() {//用于调整两个线程的执行顺序shortWait(20000);a = 1; x = b; }});Thread thread2 = new Thread(new Runnable() {@Overridepublic void run() {b = 1;y = a;}});thread1.start();thread2.start();thread1.join();thread2.join();System.out.println("第" + i + "次(" + x + "," + y + ")");if (x==0&&y==0){break;}}}public static void shortWait(long interval){long start = System.nanoTime();long end;do{end = System.nanoTime();}while(start + interval >= end);}
}

执行结果:x,y出现了0,0的结果,程序终止。出现这种结果有可能是重排序导致的。

如何保证有序性

       通过volatile 关键字保证有序性
       通过内存屏障保证有序性 
       通过synchronized关键字保证有序性
       通过Lock锁保证有序性


Java内存模型(JMM内存模型)

       Java内存模型(Java Memory Model,JMM)是Java程序中多线程并发访问共享变量时,对内存操作行为的一种规范。它定义了在多线程环境中,线程如何与主内存和工作内存交互,以确保并发程序的正确性。

              

Java内存模型的一些关键概念:

1. 主内存(Main Memory): 主内存是所有线程共享的内存区域,包含所有的共享变量。所有的线程都可以访问主内存。
2. 工作内存(Working Memory): 每个线程有自己的工作内存,存储了该线程使用到的变量的副本。线程对变量的所有操作都在工作内存中进行,不直接读写主内存。
3. 共享变量: 多个线程之间可以共享的变量,例如类的静态变量或实例变量。
4. 原子性(Atomicity): 单个的读/写操作是原子的,即要么完成,要么不开始。
5. 可见性(Visibility): 当一个线程修改了共享变量的值,其他线程应该能够立即看到这个变化。
6. 有序性(Ordering): 程序执行的顺序与代码中的顺序一致。

主内存与工作内存交互协议

从工 作内存同步到主内存之间的实现细节,Java内存模型定义了以下八种原子操作来完成:
lock(锁定):作用于主内存的变量,把一个变量标识为一条线程独占状态。
unlock(解锁):作用于主内存变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁 定。
read(读取):作用于主内存变量,把一个变量值从主内存传输到线程的工作内存中,以便随后的load动作使用
load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。
use(使用):作用于工作内存的变量,把工作内存中的一个变量值传递给执行引擎,每当虚拟机遇到一个需要 使用变量的值的字节码指令时将会执行这个操作。
assign(赋值):作用于工作内存的变量,它把一个从执行引擎接收到的值赋值给工作内存的变量,每当虚拟机 遇到一个给变量赋值的字节码指令时执行这个操作。
store(存储):作用于工作内存的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write的操 作。
write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。

Java内存模型通过以下手段来确保多线程程序的正确性:

1. 锁机制: 使用synchronized关键字或显式锁来保护共享数据,确保在同一时刻只有一个线程可以访问临界区。
2. volatile关键字: 用于修饰共享变量,保证可见性。对一个volatile变量的写操作将立即刷新到主内存,而读操作将从主内存中加载最新的值。
3. final关键字: 被final修饰的字段在构造函数结束之前就已经对其他线程可见。
4. Happens-Before关系: JMM定义了Happens-Before的规则,确保在某个操作之前的操作对其可见。

锁机制

1. 当线程获取锁时,JMM会把该线程对应的本地内存置为无效。
2. 当线程释放锁时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存中。

       synchronized关键字的作用是确保多个线程访问共享资源时的互斥性和可见性。在获取锁之前,线程 会将共享变量的最新值从主内存中读取到线程本地的缓存中,释放锁时会将修改后的共享变量的值刷 新到主内存中,以保证可见性。

volatile

1. 当写一个volatile变量时,JMM会把该线程对应的本地内存中的共享变量值刷新到主内存。
2. 当读一个volatile变量时,JMM会把该线程对应的本地内存置为无效,线程接下来将从主内存中读取共享变量。

volatile禁止指令重排序

 Happens-Before

       Happens-Before是Java内存模型(Java Memory Model,JMM)中一个重要的概念,用于规定多线程程序中操作之间的执行顺序和可见性关系。这个概念确保了在程序中对共享变量的操作是按照一定顺序执行的,以避免出现不确定的结果和数据竞争问题。

       如果操作A在操作B之前发生在之前(happens-before),那么操作A对于操作B来说,必定是可见的,而且操作A的效果将被操作B看到。  

Happens-Before部分关系规则:

1. 程序顺序规则(Program Order Rule): 在一个线程中,操作按照程序代码的先后顺序执行。
2. 锁定规则(Lock Rule): 释放锁的操作Happens-Before于后续对同一锁的加锁操作。
3. volatile变量规则(Volatile Variable Rule): 对volatile变量的写操作Happens-Before于后续对这个变量的读操作。
4. 传递性(Transitivity): 如果操作A Happens-Before于操作B,且操作B Happens-Before于操作C,那么操作A Happens-Before于操作C。
5. 线程启动规则(Thread Start Rule): 线程的启动操作Happens-Before于该线程的任何操作。
6. 线程终止规则(Thread Termination Rule): 线程的所有操作Happens-Before于其他线程检测到该线程已经终止。

相关文章:

并发编程之三大特性及JMM内存模型

目录 原子性 如何保证原子性 可见性 如何保证可见性 有序性 如何保证有序性 Java内存模型(JMM内存模型) Java内存模型的一些关键概念&#xff1a; 主内存与工作内存交互协议 Java内存模型通过以下手段来确保多线程程序的正确性&#xff1a; 锁机制 volatile volat…...

centos系统设置runlevel为5

在 CentOS 系统中&#xff0c;可以使用以下步骤将运行级别&#xff08;runlevel&#xff09;设置为 5&#xff1a; 1. 打开终端或 SSH 连接到 CentOS 服务器。 2. 以 root 用户身份登录。 3. 运行以下命令来编辑 /etc/inittab 文件&#xff1a; shell sudo vi /etc/inittab…...

关于群晖ARPL界面能出现ip但是使用Synology Assistant搜索不到ip问题 及解决方法

文章引用ing304 频道文章&#xff1a;https://qun.qq.com/qqweb/qunpro/share?_wv3&_wwv128&appChannelshare&inviteCode20jx8dPsU2z&contentID1m4NKs&businessType2&from181174&shareSource5&bizka 前言 当进入该界面后 提示IP无法访问&a…...

mysql Linux系统云服务器配置远程访问

mysql Linux系统云服务器配置远程访问 1.安装mysql 服务器 2.配置远程登录用户权限 3.进行远程登录&#xff0c;并访问数据库 1.安装mysql 服务器 首先先安装一下云服务器 sudo apt-get install mysql-server安装好之后&#xff0c;我们直接以root用户登录&#xff1a; …...

使用WAF防御网络上的隐蔽威胁之SQL注入攻击

SQL注入攻击是一种普遍存在且危害巨大的网络安全威胁&#xff0c;它允许攻击者通过执行恶意的SQL语句来操纵或破坏数据库。 这种攻击不仅能够读取敏感数据&#xff0c;还可能用于添加、修改或删除数据库中的记录。因此&#xff0c;了解SQL注入攻击的机制及其防御策略对于保护网…...

【书生·浦语】大模型实战营——第五次课程作业

基础作业——使用LMDeploy 以本地对话、网页Gradio、API服务中的一种方式部署InternLM-Chat-7B模型&#xff0c;生成300字的小故事 环境准备 除了安装所需依赖之后&#xff0c;重要的是进行模型转化&#xff08;转换成TurboMind格式&#xff09;&#xff0c;这里需要注意转化命…...

Unity | 渡鸦避难所-7 | 攻击碰撞检测

1 前言 英雄的宝剑并非只是装饰物&#xff0c;利剑出鞘时可以对怪物造成伤害。同样&#xff0c;怪物挥出铁拳时也会对英雄造成伤害。当然&#xff0c;都有同样的前提&#xff1a;在武器碰到对方的情况下&#xff0c;才会造成伤害。利用物理引擎&#xff0c;可以轻松的实现碰撞…...

Linux Mii management/mdio子系统分析之一 总体概述

Linux Mii management/mdio子系统分析之一 总体概述 &#xff08;转载&#xff09;原文链接&#xff1a;https://blog.csdn.net/u014044624/article/details/123303099 从本章开始&#xff0c;我们介绍linux的mii management对应的mdio子模块&#xff0c;该模块主要用于管理phy…...

C语言:自定义类型——联合和枚举

一、联合体 1.1 联合体类型的声明 像结构体⼀样&#xff0c;联合体也是由⼀个或者多个成员构成&#xff0c;这些成员可以是不同的类型。 声明方式如下图&#xff1a; 那联合体和结构体究竟有什么区别呢&#xff1f;&#xff1f; 下面将重点讲解联合体的特点&#xff01;&am…...

uniapp微信小程序投票系统实战 (SpringBoot2+vue3.2+element plus ) -用户投票实现

锋哥原创的uniapp微信小程序投票系统实战&#xff1a; uniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )_哔哩哔哩_bilibiliuniapp微信小程序投票系统实战课程 (SpringBoot2vue3.2element plus ) ( 火爆连载更新中... )共计21条视频…...

如何实现一个两栏布局,右侧自适应?三栏布局中间自适应?

要实现一个两栏布局&#xff0c;右侧自适应的效果&#xff0c;可以使用 CSS 的 Flexbox 或 Grid 布局来实现。以下是使用 Flexbox 实现的示例&#xff1a; HTML 结构&#xff1a; htmlCopy Code<div class"container"><div class"left-column"&…...

004 Golang-channel-practice 左右括号匹配

第四题 左右括号打印 一个协程负责打印“&#xff08;”&#xff0c;一个协程负责打印“&#xff09;”&#xff0c;左右括号的数量要匹配。在这道题目里&#xff0c;我在main函数里进行了一个死循环。会产生一个随机数&#xff0c;随机数就是接下来要打印的左括号的数量。 例…...

MS2351M/MS2351D:RF 检测器/控制器

产品简述 MS2351M/MS2351D 是一款对数放大器芯片&#xff0c;主要用于接收 信号强度指示 (RSSI) 与 控 制 功 率 放 大 器 &#xff0c; 工 作 频 率 范 围 是 0.05GHz  4.0GHz &#xff0c;动态范围随信号频率不同可达 35dB 到 45dB 。 MS2351M/MS2351D 是电压响…...

vue中使用js-doc

安装依赖 安装vue-template-compiler npm install ​vue-template-compiler​ 安装minami npm install minami 安装js-doc npm install js-doc 根目录下创建 .jsdoc.conf.json 内容&#xff1a; {"tags": {"allowUnknownTags": true,// 指定所用词…...

Hive知识点

基本概念&#xff1a; 由Facebook开源&#xff0c;构建在Hadoop之上的数据仓库&#xff0c;数据计算是mapreduce&#xff0c;数据存储是HDFS 目的是构建面向分析的集成的数据环境&#xff0c;为企业提供决策支持 &#xff08;面向分析的存储系统&#xff09; 主要特征&…...

android自启动

Android 开机自动启动一个Service 附源码_watchdogservice-CSDN博客 执行 adb push 本地地址 目标地址 时遇到错误&#xff1a; adb: error: failed to copy app-release.apk to /system/app/app-release.apk: remote couldnt create file: Read-only file system 解决方案…...

cookie、Web Storage

前端知识汇编 1. cookie1.1 cookie的限制1.2 cookie的构成1.3 JavaScript中的cookie1.4 子cookie1.5 使用cookie的注意事项 2. Web Storage2.1 Storage类型2.2 sessionStorage对象2.3 localStorage对象2.4 存储事件2.5 限制 1. cookie cookie是客户端与服务器端进行会话时使用…...

【rk3568】01-环境搭建

文章目录 1.开发板介绍1.1相关资源&#xff1a;1.2接口布局1.3屏幕1.4核心板引脚可复用资源 2.环境搭建2.1安装依赖包2.2git配置2.3安装sdk2.4sdk介绍2.5sdk编译 3.镜像介绍 1.开发板介绍 开发板&#xff1a;atk-rk3568开发板 eMMC&#xff1a;64G LPDDR4&#xff1a;4G 显示屏…...

编程笔记 html5cssjs 036 CSS概述

编程笔记 html5&css&js 036 CSS概述 一、什么是 CSS?二、样式非常重要三、CSS 语法四、CSS 注释五、示例 CSS (Cascading Style Sheets&#xff0c;层叠样式表&#xff09;&#xff0c;是一种用来为结构化文档&#xff08;如 HTML 文档或 XML 应用&#xff09;添加样式…...

Vue入门七(Vuex的使用|Vue-router|LocalStorage与SessionStorage和cookie的使用)

文章目录 一、Vuex1&#xff09;理解vuex2&#xff09;优点3&#xff09;何时使用&#xff1f;4&#xff09;使用步骤① 安装vuex② 注册vuex③ 引用vuex④ 创建仓库Store五个模块介绍 5&#xff09;基本使用 二、Vue-router三、LocalStorage与SessionStorage、cookie的使用 一…...

Mybatis逆向工程,动态创建实体类、条件扩展类、Mapper接口、Mapper.xml映射文件

今天呢&#xff0c;博主的学习进度也是步入了Java Mybatis 框架&#xff0c;目前正在逐步杨帆旗航。 那么接下来就给大家出一期有关 Mybatis 逆向工程的教学&#xff0c;希望能对大家有所帮助&#xff0c;也特别欢迎大家指点不足之处&#xff0c;小生很乐意接受正确的建议&…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

Python 实现 Web 静态服务器(HTTP 协议)

目录 一、在本地启动 HTTP 服务器1. Windows 下安装 node.js1&#xff09;下载安装包2&#xff09;配置环境变量3&#xff09;安装镜像4&#xff09;node.js 的常用命令 2. 安装 http-server 服务3. 使用 http-server 开启服务1&#xff09;使用 http-server2&#xff09;详解 …...

如何通过git命令查看项目连接的仓库地址?

要通过 Git 命令查看项目连接的仓库地址&#xff0c;您可以使用以下几种方法&#xff1a; 1. 查看所有远程仓库地址 使用 git remote -v 命令&#xff0c;它会显示项目中配置的所有远程仓库及其对应的 URL&#xff1a; git remote -v输出示例&#xff1a; origin https://…...

算法刷题-回溯

今天给大家分享的还是一道关于dfs回溯的问题&#xff0c;对于这类问题大家还是要多刷和总结&#xff0c;总体难度还是偏大。 对于回溯问题有几个关键点&#xff1a; 1.首先对于这类回溯可以节点可以随机选择的问题&#xff0c;要做mian函数中循环调用dfs&#xff08;i&#x…...

Oracle实用参考(13)——Oracle for Linux物理DG环境搭建(2)

13.2. Oracle for Linux物理DG环境搭建 Oracle 数据库的DataGuard技术方案,业界也称为DG,其在数据库高可用、容灾及负载分离等方面,都有着非常广泛的应用,对此,前面相关章节已做过较为详尽的讲解,此处不再赘述。 需要说明的是, DG方案又分为物理DG和逻辑DG,两者的搭建…...

Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术点解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、Spring MVC与MyBatis技术点解析 第一轮&#xff1a;基础概念问题 请解释Spring框架的核心容器是什么&#xff1f;它的作用是什么&#xff1f; 程序员JY回答&#xff1a;Spring框架的核心容器是IoC容器&#xff08;控制反转…...