Java并发编程(2)-线程安全之共享对象解读

Java必知必会系列:并发编程与线程安全 作者:禅与计算机程序设计艺术 1.简介 随着计算机的发展,人们越来越多地将注意力投向了并发编程,这是因为并发编程能够极大的提升系统的性能、响应能力及资源利用率等。 但是,由于多线程编程存在众多复杂的技术细节,并且在某些情况下容易造成错误导致系统崩溃甚至死锁等严重后果,因此掌握正确的线程同步 阅读详情


更多关于Java并发编程的文章请点击这里:Java并发编程实践(0)-目录页


在上一篇关于线程安全概述的文章中提到过,编写正确的并发程序的关键在于对共享的、可变状态的变量进行访问管理,上一篇着重讲解使用同步来避免多个线程在同一时间访问同一数据;这一篇将讲解共享和发布对象的技术,使多个线程能够安全地访问他们。
本文内容均总结自《Java并发编程实践》第三章 共享对象 章节的内容 ,详情可以查阅该书。

一、变量可见性

1.1、共享对象的可见性

阅读下面的代码,运行main方法后,会出现什么结果?

public class ThreadTest{
	private static  boolean ready;
	private static  int i;
	
	public static void main(String[] args) {
		new MyThread().start();
		i = 1;
		ready = true;
	}
	
	public static class MyThread extends Thread{
		public void run(){
			if(!ready){
				Thread.yield();
			}
			System.out.println(i);
		}
	}
}

main方法是写入数据的线程,而MyThread是读取数据的线程,由于没有适当同步操作,两个线程之间发生了读写的分离,而通常来说,当读和写分离为两个线程时,不能保证读线程能及时地读取到其他线程写入的值,甚至说不可能。为了保证读写线程的值能共享,必须使用同步机制。

1.2 、volatile变量

锁不仅仅是关于同步和互斥的,也是关于内存可见的。为了保证所有的线程都能够看到其共享的、可变变量的最新值,读取和写入线程必须使用公共的锁进行同步。
Java语言也提供了其他的选择,即一种同步的弱形式:volatile变量。它确保变量的更新以可预见的方式告知其他线程。当一个域声明为volatile类型后,编译器与运行时会监视这个变量;volatile变量不会缓存在寄存器或者缓存在对其它处理器隐藏的地方。所以,读一个volatile类型的变量时,总会返回由某一线程所写入的最新值。

以下的数羊程序简单说明volatile变量。

private volatile boolean asleep;
	//是羊则数羊
	while(!asleep){
		countSomeSheep();
	}

volatile变量通常被当做标识完成、中断、状态的标记使用,如上面程序中的asleep标记。尽管volatile也可以用来标识其他类型的状态信息,但是必须十分小心。比如,volatile的语义不足以使自增查找(count++)原子化,除非你能保证只有一个线程对变量执行写查找。原子变量(atomic variable)提供“读-写-改”的原子查找的支持,而且常被用作更优的volatile变量。

只有满足了下面所有标准后才能使用volatile变量:

写入变量时并不依赖变量的当前值;或者能够保证只有单一的线程改变的值;

变量不需要与其他的状态变量共同参与不变约束;

访问变量时,没有其他的原因需要加锁。

二、变量发布与逸出

发布一个对象的意思是使它能够被当前范围之外的代码所使用。比如将一个引用存储到其他代码可以访问到的地方。

2.1、如何发布对象

最常见的发布对象方式是将对象的引用存储到公共静态域中。任何类和线程都能够看到这个域:

public static Set<Secret> knownSecrets;
	public void initialize(){
		knownSecrets = new HashSet<Secret>();
}
2.2、发布对象带来的this引用逸出

并发编程实践中,this引用逃逸("this"escape)是指对象还没有构造完成,它的this引用就被发布出去了。这是危及到线程安全的,因为其他线程有可能通过这个逸出的引用访问到“初始化了一半”的对象(partially-constructed object)。这样就会出现某些线程中看到该对象的状态是没初始化完的状态,而在另外一些线程看到的却是已经初始化完的状态,这种不一致性是不确定的,程序也会因此而产生一些无法预知的并发错误。( 详情可阅读《Java并发编程实践》)

三、线程封闭

访问共享的、可变的数据要求使用同步。一个可以避免同步的方式就是不共享数据。如果数据仅在单线程中被访问到,就不需要任何同步。线程封闭(Thread confinement)技术是在实现线程安全的最简单的方式之一。当对象封闭在一个线程中时,这种做法会自动成为线程安全的。

3.1、Ad-hoc 线程限制

Ad-hoc线程封闭是指,维护线程封闭性的职责完全由程序实现来承担。Ad-hoc线程封闭是非常脆弱的,因为没有任何一种语言特性,例如可见性修饰符或局部变量,能将对象封闭到目标线程上。事实上,对线程封闭对象(例如,GUI应用程序中的可视化组件或数据模型等)的引用通常保存在公有变量中。(详情可阅读《Java并发编程实践》)

3.2、使用 ThreadLocal

一种维护线程限制的更加规范的方式是使用TheadLocal,它允许将每个线程与持有数值的对象关联在一起。ThreadLocal提供了get和set访问器,为每个使用它的线程维护一份单独的拷贝。所以get总是返回由当前执行线程通过set设置的最新值。(详情可阅读 http://www.cnblogs.com/dolphin0520/p/3920407.html)

四、如何安全地共享对象

为了安全地发布对象,对象的引用以及对象的状态必须同时对其他线程可见。一个正确创建的对象可以通过下列条件安全地发布:

通过静态初始化器初始化对象的引用;

将它的引用存储到volatile域或AtomicReference;

将它的引用存储到正确创建的对象的final域中;

将它的引用存储到由锁保护的域中。

在并发程序中,使用和共享对象的一些有效策略:

线程限制:一个线程限制的对象,通过限制在线程中,而被线程独占,并且只能被占有它的线程修改。

共享只读:一个共享的只读对象,在没有额外同步的情况下,可以被多个线程兵法地访问,但是任何线程都不能修改它。

共享线程安全:一个线程安全的对象在内部进行同步,所以其他线程无须额外同步,就可以通过公共接口随意地访问它。

被守护的:一个被守护的对象只能通过特定的锁来访问。
深入探索Java并发编程 Java并发编程是构建高性能应用不可或缺的一部分,它允许开发者利用多核处理器的优势来提高应用的响应性和吞吐量。在这一章中,我们将为读者介绍并发编程的基本概念,以及它在现代Java应用程序中的重要性。 阅读详情

相关推荐

《惠普工作站设置BIOS从U盘装系统》

惠普工作站设置BIOS 惠普工作站在做服务器时应用广泛,本文介绍下其BIOS开机自启动设置,附上图片,以供学习参考。 惠普工作站设置BIOS 启动步骤如下: 第一步:根据需要对BIOS进行更改,并保存 1.重启工作站按F10进入BIOS设置(也可以按ESC键选择进入BIOS设置的选项)。 图1 惠普工作站B...

istrangeboy&begin zero的博客 2万+

Java并发编程详解之 线程安全和对象共享

一、简单介绍 在我们用框架编程的过程中,经常不用太关注多线程问题,这是因为例如Servlet和RMI(Remote Method Invocation,远程方法调用),RMI使得代码能够调用其他JVM中的运行的对象。这些框架负责解决一些细节问题,例如请求管理、线程创建、负载均衡,并在正确的时刻将请求分发给正确的应用程序组件。编写Servlet的开发人员不需要了解有多少请求在同一时刻要被处理,也不

Jackson Zhang 8387

实例讲解Simulink CAN通讯丢失故障判定模型搭建及仿真测试验证方法

本文通过ABS通讯丢失故障触发、判定条件Simulink模型的搭建和仿真的讲解,介绍了一种控制器CAN通讯丢失故障判定的方法和建模方法,希望能给相关技术人员带来一定参考和帮助。

qq_43011586的博客 3686

安全共享对象策略

u013208718的博客 365

RV1126 MIPI CSI-2驱动RGB888图像采集的V4L2实战解析

本文详细解析了在RV1126平台上通过MIPI CSI-2接口采集RGB888格式图像的完整V4L2实战流程。核心内容包括设备树(DTS)配置、内核驱动适配、Media Controller链路调试,以及使用v4l2-ctl工具进行图像抓取与验证的方法,旨在帮助开发者打通从硬件连接到稳定采集RGB888图像数据的关键环节。

weixin_29161719的博客 166

Qlib:微软开源的AI量化投资平台 极简入门快速上手教程:使用 Qlib 进行中芯国际股价回测和预测

Qlib是由微软开源的面向AI量化投资的工具包。它提供了构建量化投资模型所需的基础设施,旨在帮助研究者和从业人员更高效地进行量化研究和策略开发。

AI天才研究院 5420

线程安全和对象共享

一、线程安全类 1.定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协调,这个类都能表现出正确的行为,那么就称这个类是线程安全类。2.确保线程安全的方法 (1)无状态对象:不包含任何域,也不包含任何对其他类中的域的引用。计算过程中的临时状态仅存在于线程栈上的局部变量中,并且只能由正在执行的线程访问。public cla

shieryujian的博客 626

【ComfyUI专栏】ComfyUI 常用工作流下载与分享网址

首先我们来分享第一个网站,Openart 网站,这个网站同时也能提供比较多的其他类型。但是如果希望下载工作流,我们可以访问到如下的这个站点。作为ComfyUI的学习用户来说,我们通常需要借助他山之石来帮助我们快速成长,因此我们需要找到能够分享和下载的网址。,当前网站是综合性网站,在网站中可以下载各种不同的类型,其中工作流只是可以下载的非常小的部分。这个网站也可以浏览不同的工作流,这个工作流的地址和访问如下的站点。

技术与管理的平衡木- 7820

《Java并发编程实战》线程安全性和对象共享

引言 多进程和多线程的优点? 多线程的优势与风险? 竞态条件是什么? 早期计算机中还不存在操作系统,一台机器从头到尾只能执行一个程序,并且这个程序能访问所有的计算机资源。 操作系统的引入是的计算机“同时”能运行多个程序,不同程序都在单独的进程中运行:操作系统为各个独立的进程分配各种资源,包括内存、文件句柄以及安全证书等。不同进程之间可以通过一些粗粒度的通信机制来交换数据,包括:套接字、信号...

Ethan Zeng 博客空间 534

小卫星多普勒频偏MATLAB代码

多普勒频偏是由于发射机和接收机之间的相对运动而引起的频率变化。对于小卫星,由于其速度和高度的变化,多普勒频偏会变得更加明显。本文将探讨小卫星多普勒频偏的原理、影响因素以及补偿方法。多普勒频偏的原理当发射机和接收机之间存在相对运动时,接收到的信号频率会发生变化。这种频率变化称为多普勒频偏。其原理可以描述如下:设发射机和接收机之间的距离为 d,发射信号的频率为 f0,发射机和接收机的相对速度为 v。则接收到的信号频率 f 为:其中 c 为光速。

qq_59747472的博客 245

GEE生物量预测:利用多源遥感数据和随机森林算法RF构建地上生物量(AGB)预测模型,并实现未来年份的生态变化模拟(大面积生物量反演)

数据融合策略:整合5类遥感产品(AGB、NDVI、LAI、土地覆盖、地形)时序特征构建:采用生长季中值法降低云污染影响机器学习优化分层采样保证数据代表性80棵决策树平衡精度与效率预测可靠性基准期R²达0.76需结合地面实测数据校正。

此星光明博客 419

【Java并发编程】线程安全和共享对象

一、什么是线程安全   当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用代码代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类是线程安全的。   内部锁   Java提供了强制性的内置锁机制:synchronized块。一个synchronized块有两个部分:锁对象的引用,以及这个锁保护的代码块。执行线程进入synchronized块之前会自动获得锁,无论通过正常控制路径退出还是从块中抛出异常,线程都在放弃对synchronized块

m0_67659981的博客 330

基于YOLOv26的智能农业无人机巡检系统

本文提出了一种基于YOLOv26的智能农业无人机巡检系统。系统采用模块化设计,包含数据采集、预处理、目标检测、图像拼接、分析决策和部署控制六大核心模块。无人机搭载多光谱相机、RGB相机和热红外相机进行农田数据采集,通过YOLOv26实现作物病虫害、杂草及灌溉设备的检测。系统采用PyTorch、OpenCV等技术栈,支持无人机自动路径规划和多传感器数据采集,并包含数据增强和预处理功能。该系统可有效提升农业巡检效率,为精准农业提供智能化解决方案。

一键难忘的博客 810

JAVA并发编程实战——共享对象

目录1. 可见性1. 1 过期数据1.2 锁和可见性1.3 Volatile变量2. 发布和逸出2.1 安全构建实践3. 线程封闭3.1 栈限制3.2 ThreadLocal4. 不可变性5 安全发布的模式参考文献 1. 可见性 内存可见性:当一个线程修改使用的共享对象,其它线程能够看到改变 以下面demo为例: public class NoVisibility { private static boolean ready; private static int number;

qq_36566262的博客 1361

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

【Java并发编程一】线程安全和共享对象

一、什么是线程安全   当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用代码代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类是线程安全的。   内部锁   Java提供了强制性的内置锁机制:synchronized块。一个synchronized块有两个部分:锁对象的引用,以及这个锁保护的代码块。执行线程进入syn...

dengduoya4019的博客 257

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

Java并发编程实战总结

Java并发编程

qq_39817635的博客 1547

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

【Java并发编程一】线程安全

什么是线程安全? 当多个线程访问一个类时,如果不用考虑这些线程在运行时环境下的调度和交替执行,并且不需要额外的同步及在调用代码代码不必作其他的协调,这个类的行为仍然是正确的,那么称这个类是线程安全的。 内部锁 Java提供了强制性的内置锁机制:synchronized块。一个synchronized块有两个部分:锁对象的引用,以及这个锁保护的代码块。执行线程进入synchronized块

706

《JUC并发编程 - 高级篇》03 - 共享对象之管程 上篇(共享带来的问题 | synchronized | 线程八锁 | 线程安全类)

《JUC并发编程 - 高级篇》03 - 共享对象之管程 上篇(共享带来的问题 | synchronized | 线程八锁 | 线程安全类)

LXYDSF的博客 486

并发编程之线程安全

当线程去争抢对象的锁时,该对象锁已经被占用,当前线程就会循环等待,不断的去判断锁是否能够被获取,如果不能被获取,直到成功获取锁才会退出循环;:在修改数据时如果发现数据和之前获取的不一致,则读最新数据,修改后重试修改;:假定会发生并发冲突,同步所有对数据的相关操作,从读数据就开始上锁;):给资源加上写锁,线程可以修改资源,其他线程不能再加锁;(单写):给资源加上读锁后只能读不能改,其他线程也只能加读锁,不能加写锁;(多读):线程拿到一把锁之后,可以自由进入同一把锁所同步的其他代码。

RubyWinner的博客 1013

关于Java并发编程的总结和思考

编写优质的并发代码是一件难度极高的事情。Java语言从第一版本开始内置了对多线程的支持,这一点在当年是非常了不起的,但是当我们对并发编程有了更深刻的认识和更多的实践后,实现并发编程就有了更多的方案和更好的选择。本文是对并发编程的一点总结和思考,同时也分享了Java 5以后的版本中如何编写并发代码的一点点经验。

骆昊的技术专栏 16万+

java并发编程实战

《Java并发编程实战》

weixin_50811484的博客 1040

java并发编程实践学习(2)共享对象

java并发

c1137889088的博客 301

Java并发编程实战 读书笔记

线程的优点恰当使用线程,可以提升复杂程序的性能,降低开发和维护成本可以把一部分复杂代码转为直接、简洁易懂的代码更有效地利用空闲处理器资源,提高吞吐量用户界面有更好的响应性线程的缺点安全性(synchronized解决)活跃度:死锁、饥饿、活锁性能,上下文切换。

m0_49499183的博客 696

【并发编程-基础】(五)线程安全策略

文章目录一、不可变对象final1.1、不可变对象需要满足的条件1.2、创建一个不可变对象的方法1.3、`Collections` 的 `unmodifiable` (JDK的不可变集合)1.3.1、实例:1.3.2、输出1.3.2、解析1.4、`Google Guava` 的 `Immutable` (不可变集合)1.4.1、实例1.4.2、输出结果1.4.3、解析1.5、 `unmodif...

tangxz的博客 864

Java并发编程(一)线程安全的类的特性

线程安全的类是我们很希望达到的特性,那怎么才能判断以及设计一个线程安全的类,是我们需要关注的问题。 这章中我会总结线程安全的类所具有的特性以及应该避免哪些问题。

FrankLee的博客 466
上一篇: Java并发编程(1)-线程安全基础入门知识
下一篇: Java并发编程(3)-如何构造线程安全应用
BoringRong
BoringRong 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 2万+粉丝 386原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BoringRong

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值