JavaEE之线程(5)——Java内存模型、内存可见性、volatile关键字

news2024/11/20 2:36:17

前言

volatile可以理解成轻量级的 synchronized, 它在多CPU开发中保证了共享变量的“可见性”,可见性我们可以理解成是:当一个线程修改一个共享变量时,另一个线程可以读到这个修改的值。由于它不会引起线程的上下文切换和调度,所以如果对volatile使用恰当的话,它比synchronized的使用成本更低。


一、内存可见性和内存模型

1.1内存可见性

基本概念:
 可见性是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果,另一个线程马上就能看到

1.2 内存模型(重点)

 Java 内存模型 (JMM):Java虚拟机规范中定义了Java内存模型目的是屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果。
线程,主内存,工作内存的交互关系如图所示:
在这里插入图片描述
简单来说:

  1. 所有变量储存在主内存。
  2. 每条线程拥有自己的工作内存,其中保存了主内存中线程使用到的变量的副本。
  3. 线程不能直接读写主内存中的变量,所有操作均在工作内存中完成。

由上述内容可知,每个线程有自己的工作内存,这些工作内存中的内容相当于同一个共享变量的 “副本”。
(1)此时修改线程1 的工作内存中的值,线程2 的工作内存不一定会及时变化,如下图所示:
在这里插入图片描述
(2)一旦线程1 修改了 a 的值,此时主内存不一定能及时同步。对应的线程2 的工作内存的 a 的值也不一定能及时同步。此时,这个时候代码中就容易出现问题。
在这里插入图片描述

二、volatile关键字

 在上面,我们介绍了内存可见性问题,我们在写入 volatile 修饰的变量的时候

代码在写入 volatile 修饰的变量的时候;
将改变后的副本的值从工作内存刷新到主内存

代码在读取 volatile 修饰的变量的时候

从主内存中读取volatile变量的最新值到线程的工作内存中
从工作内存中读取volatile变量的副本

下面我们从一个实例来详细介绍volatile关键字

static class Counter {
	public int flag = 0;
}
public static void main(String[] args) {
	Counter counter = new Counter();
	
	Thread t1 = new Thread(() -> {
		while (counter.flag == 0) {
		// do nothing
	}
	System.out.println("循环结束!");
	});
	
	Thread t2 = new Thread(() -> {
		Scanner scanner = new Scanner(System.in);
		System.out.println("输入一个整数数:");
		counter.flag = scanner.nextInt();
	});
	t1.start();
	t2.start();
}

----------------------------------------------------
// 执行效果
// 当用户输入非0值时, t1 线程循环不会结束. (这显然是一个 bug)

此时,t1 读的是自己工作内存中的内容,当 t2 对 flag 变量进行修改,此时 t1 感知不到 flag 的变化。
但是如果给变量加上volatile关键字,代码就不会出错:

static class Counter {
	public volatile int flag = 0;
}
-----------------------------------
// 执行效果
// 当用户输入非0值时, t1 线程循环能够立即结束.

三、volatile 不保证原子性

volatile 和 synchronized 有着本质的区别.,synchronized 能够保证原子性, volatile 保证的是内存可见性。
比如,我们对上面的代码进行调整:去掉 flag 的 volatile,给 t1 的循环内部加上 synchronized,并借助 counter 对象加锁。

static class Counter {
	public int flag = 0;
}

public static void main(String[] args) {
	Counter counter = new Counter();
	Thread t1 = new Thread(() -> {
		while (true) {
			synchronized (counter) {
				if (counter.flag != 0) {
					break;
				}
			}
			// do nothing
		}
		System.out.println("循环结束!");
	});
	Thread t2 = new Thread(() -> {
		Scanner scanner = new Scanner(System.in);
		System.out.println("输入一个整数:");
		counter.flag = scanner.nextInt();
	});
	t1.start();
	t2.start();
}

总结

 以上就是今天要讲的内容,在并发三特征的可见性中,volatile通过新值立即同步到主内存和每次使用前从主内存刷新机制保证了可见性。通过禁止指令重排序保证了有序性。无法保证原子性;
 synchronized关键字通过lock和unlock操作保证了原子性,通过对一个变量unlock前,把变量同步回主内存中保证了可见性,通过一个变量在同一时刻只允许一条线程对其进行lock操作保证了有序性

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

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

相关文章

arp icmp 等报文格式

ARP报文格式 ARP是一个独立的三层协议,所以ARP报文在向数据链路层传输时不需要经过IP协议的封装,而是直接生成自己的报文,其中包括ARP报头,到数据链路层后再由对应的数据链路层协议(如以太网协议)进行封装…

[第五空间 2021]WebFTP

目录扫描git泄露phpinfo.php 一开始想到是sql注入,但是不行。目录扫描,发现 .git 和 phpinfo.php 访问phpinfo.php,ctrlf 搜索 flag,找到 flag。

Pyqt中QThread传递自己定义的参数、类、函数

Pyqt中QThread传递自己定义的参数、类、函数 1 pyqt中Qthread传递自己定义的参数2 pyqt中Qthread传递自己定义的类3 pyqt中Qthread传递自己定义的函数4 pyqt中Qthread内部定义自己的函数5 pyqt中Qthread传递参数到内部定义自己的函数 1 pyqt中Qthread传递自己定义的参数 在PyQ…

选择法(数值排序)(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//声明排序函数sort; void sort(int a[], int n);int main() {//初始化变量值&#xff1b;int i, a[10];//填充数组&#xff1b;printf("请输入10个整数\n&…

C语言错题本之<结构体>

以下叙述中正确的是________. A)预处理命令行必须位于源文件的开头 B)在源文件的一行上可以有多条预处理命令 C)宏名必须用大写字母表示 D)宏替换不占用程序的运行时间 答案&#xff1a;D 解析&#xff1a; A&#xff1a;在C、C等编程语言中&#xff0c;预处理指令&#xff08;…

轻松掌握抖音自动点赞技巧,快速吸粉

在当今这个信息爆炸的时代&#xff0c;抖音作为短视频领域的领头羊&#xff0c;不仅汇聚了庞大的用户群体&#xff0c;也成为了品牌和个人展示自我、吸引粉丝的重要平台。如何在众多内容创作者中脱颖而出&#xff0c;实现高效引流获客&#xff0c;精准推广自己的内容&#xff0…

springboot+vue+mybatis台球俱乐部管理系统的设计与实现+PPT+论文+讲解+售后

随着信息技术在管理上越来越深入而广泛的应用&#xff0c;作为一般的台球厅都会跟上时代的变化&#xff0c;用上计算机来代表重复性的劳动&#xff0c;并且给用户一种新奇的感受&#xff0c;实现台球俱乐部系统 在技术上已成熟。本文介绍了台球俱乐部系统 的开发全过程。通过分…

Jmeter+Grafana+Prometheus搭建压测监控平台

本文不介绍压测的规范与技术指标&#xff0c;本文是演示针对Jmeter如何将压测过程中的数据指标&#xff0c;通过Prometheus采集存储&#xff0c;并在Granfan平台进行仪表盘展示; 介绍 系统压测属于日常项目开发中的一个测试环节&#xff0c;使用测试工具模拟真实用户行为&…

【C++】 C++ 编写 鸡兔同笼程序

文章目录 “鸡兔同笼”问题是一个经典的数学问题&#xff0c;要求根据总头数和总腿数来计算鸡和兔的数量。假设鸡有 2 条腿&#xff0c;兔有 4 条腿。可以通过以下步骤求解这个问题&#xff1a; 1 .设鸡的数量为 x&#xff0c;兔的数量为 y。2.根据题意&#xff0c;我们有以下…

CentOS7中如何docker-compose

在 CentOS 7 上安装 docker-compose 需要几个步骤 步骤 1: 安装 Docker 首先&#xff0c;确保你已经安装了 Docker。如果没有安装&#xff0c;可以通过以下命令安装&#xff1a; sudo yum update -y sudo yum install -y yum-utils sudo yum-config-manager --add-repo http…

老铁,对不住了,没有B端成品界面可售,都是定制化设计

经常有粉丝老铁问我有没有成品的UI图可以出售&#xff0c;实在对不住&#xff0c;我们不销售设计成品。 UI设计图是一种设计稿&#xff0c;它是用来展示和呈现产品的界面设计和交互效果的&#xff0c;而不是一个完整的、可交付的成品。UI设计图通常是以静态的形式呈现&#xf…

基于springboot+vue+Mysql的在线答疑系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

CS144 Checkpoint 4: interoperating in the world(2024)

分析网络路径和性能&#xff1a; mtr命令 mtr 输出的详细分析&#xff1a; mtr 162.105.253.58 命令用于结合 traceroute 和 ping 的功能&#xff0c;实时监测并分析从你的计算机到目标主机&#xff08;IP 地址 162.105.253.58&#xff0c;北京大学计算中心&#xff09;之间…

vscode 之 output 输出中文乱码,终端输出中文正常

# 1. 背景 因为没钱买正版的软件&#xff0c;所以转战 vscode 编译器。 在编译 python 文件时&#xff0c;发现直接右键 runner code&#xff0c;输出中文乱码。 但是在 teiminal 终端 执行py test.py 时&#xff0c;输出正常&#xff0c;中文正常。 output 输出中文样式(中文…

JAVA实验项目(二): 抽象类、接口的定义与使用

实验项目二 抽象类、接口的定义与使用 Tips&#xff1a;"分享是快乐的源泉&#x1f4a7;&#xff0c;在我的博客里&#xff0c;不仅有知识的海洋&#x1f30a;&#xff0c;还有满满的正能量加持&#x1f4aa;&#xff0c;快来和我一起分享这份快乐吧&#x1f60a;&…

【算法优选】 动态规划之子数组、子串系列——壹

文章目录 &#x1f38b;前言&#x1f38b;最大子数组和&#x1f6a9;题目描述&#x1f6a9;算法思路&#x1f6a9;代码实现 &#x1f334;环形子数组的最大和&#x1f6a9;题目描述&#x1f6a9;算法思路&#xff1a;&#x1f6a9;代码实现 &#x1f332;乘积最大子数组&#x…

大模型应用的最佳实践Chains, Chain代码剖析、llmchain示例

各种chain的介绍 串联式编排调用链:SequentialChain 流水线 胶水代码逻辑处理具备编排逻辑 串行 one by one的调用上一个chain的输出 作为 下一个chain的输入 超长文本的转换 Transform Chain pdf文件处理提供了套壳的能力 将python处理字符串的能力 套用进来 完成数据的格式化…

C++面向对象程序设计-北京大学-郭炜【课程笔记(八)】

C面向对象程序设计-北京大学-郭炜【课程笔记&#xff08;八&#xff09;】 1、虚函数和多态的基本概念1.1、虚函数1.2、多态多态的表现形式一多态的表现形式二 2、多态实例&#xff1a;魔法门之英雄无敌2.1、**非多态的实现方法&#xff1a;**2.2、**多态的实现方法** 3、多态实…

汇昌联信:拼多多网店该如何开店?

拼多多网店的开设流程并不复杂&#xff0c;但需要细心和耐心去完成每一步。下面将详细阐述如何开设一家拼多多网店。 一、选择商品与定位 开设拼多多网店的第一步是确定你要销售的商品类型&#xff0c;这决定了你的目标客户群体和市场定位。你需要了解这些商品的市场需求、竞争…

MacApp自动化测试之Automator初体验

今天我们继续讲Automator的使用。 初体验 启动Automator程序&#xff0c;选择【工作流程】类型。从资源库区域依次将获取指定的URL、从网页中获得文本、新建文本文件三个操作拖进工作流创建区域。 然后修改内容&#xff0c;将获取指定的URL操作中的URL替换成https://www.cnb…