final的安全发布
final的安全发布
两个关键字“发布”“安全”
所谓发布通俗一点的理解就是创建一个对象,使这个对象能被当前范围之外的代码所使用
比如Object o = new Object();
然后接下来使用对象o
但是对于普通变量的创建,之前分析过,大致分为三个步骤:
1、分配内存空间
2、将o指向分配的内存空间
3、调用构造函数来初始化对象
这三个步骤不是原子的,如果执行到第二步,还没有进行初始化,此时对象已经不是null了,如果被其他代码访问,这将收获一个错误的结果。
或者说对象尚未完全创建就被使用了,其他线程看到的结果可能是不一致的,这就是不安全的发布
根本原因就是JVM创建对象的过程涉及到分配空间、指针设置、数据初始化等步骤,并不是同步的,涉及到主存与缓存、处理器与寄存器等,可见性没办法得到保障
所以说,什么是安全发布,简单理解就是对象的创建能够保障在被别人使用前,已经完成了数据的构造设置,或者说一个对象在使用时,已经完成了初始化。
不幸的是,Java对此并没有进行保障,你需要自己进行保障,比如synchronized关键字,原子性、排他性就可以做到这一点
不安全的发布实例
怎么保障安全发布?有几种方法:
一种是刚才提到的锁机制,通过加锁可以保障中间状态不会被读取
另外还有:
1、借助于volatile或者AtomicReference声明对象
2、借助于final关键字
3、在静态初始化块中,进行初始化(JVM会保障)
4、将对象引用保存到一个由锁保护的域中
5、借助AtomicReference
很显然,对于锁机制,那些线程安全的容器比如ConcurrentMap,也是满足这条的,所以也是安全发布
对于final,当你创建一个对象时,使用final关键字能够使得另一个线程不会访问到处于“部分创建”的对象
因为:当构造函数退出时,final字段的值保证对访问构造对象的其他线程可见
如果某个成员是final的,JVM规范做出如下明确的保证:
一旦对象引用对其他线程可见,则其final成员也必须正确的赋值
所以说借助于final,就如同你对对象的创建访问加锁了一般,天然的就保障了对象的安全发布。
对于普通的变量,对象的内存空间分配、指针设置、数据初始化,和将这个变量的引用赋值给另一个引用,之间是可能发生重排序的,所以也就导致了其他线程可能读取到不一致的中间状态
但是对于final修饰的变量,JVM会保障顺序
不会在对final变量的写操作完成之前,与将变量引用赋值给其他变量之间进行重排序,也就是final变量的设置完成始终会在被读取之前
final除了不可变的定义之外,还与线程安全发布息息相关
借助于final,可以达到对象安全发布的保障,只需要借助于final,不在需要任何额外的付出,他能够保障在多线程环境下,总是能够读取到正确的初始化的值
所以,如果你不希望变量后续被修改,你应该总是使用final关键字
而且,很显然在某些场景下,final也可以解决一定的安全问题
实例
使用synchronized锁的时候,作为锁的对象最好要加上final修饰符,因为可能线程会改变锁变量持有的具体的对象。
demo如下:
public class Test02 {
static Object lock = new Object();
public static void main(String[] args) {Thread t1 = new Thread(() -> {lock = new Object();synchronized (lock) {for (int i = 0; i < 10; i++) {try {Thread.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("A");}}});Thread t2 = new Thread(() -> {lock = new Object();synchronized (lock) {for (int i = 0; i < 10; i++) {try {Thread.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("B");}}});t1.start();t2.start();
}
}
但是要是把锁改成final的。代码如下:
public class Test02 {static final Object lock = new Object();public static void main(String[] args) {Thread t1 = new Thread(() -> {
// lock = new Object(); // 编译出错,final不能修改synchronized (lock) {for (int i = 0; i < 10; i++) {try {Thread.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("A");}}});Thread t2 = new Thread(() -> {
// lock = new Object();synchronized (lock) {for (int i = 0; i < 10; i++) {try {Thread.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("B");}}});t1.start();t2.start();}
}
实例参考:https://juejin.cn/post/7104070219806539806
原理参考:https://www.cnblogs.com/noteless/p/10416678.html
相关文章:
final的安全发布
final的安全发布 两个关键字“发布”“安全” 所谓发布通俗一点的理解就是创建一个对象,使这个对象能被当前范围之外的代码所使用 比如Object o new Object(); 然后接下来使用对象o 但是对于普通变量的创建,之前分析过,大致分为三个步骤&am…...
3易懂AI深度学习算法:长短期记忆网络(Long Short-Term Memory, LSTM)生成对抗网络 优化算法进化算法
继续写:https://blog.csdn.net/chenhao0568/article/details/134920391?spm1001.2014.3001.5502 1.https://blog.csdn.net/chenhao0568/article/details/134931993?spm1001.2014.3001.5502 2.https://blog.csdn.net/chenhao0568/article/details/134932800?spm10…...

云计算 云原生
一、引言 云计算需要终端把信息上传到服务器,服务器处理后再返回给终端。在之前人手一台手机的情况下,云计算还是能handle得过来的。但是随着物联网的发展,什么东西都要联网,那数据可就多了去了,服务器处理不过来&…...

深拷贝、浅拷贝 react的“不可变值”
知识获取源–晨哥(现实中的人 嘿嘿) react中如果你想让一个值始终不变 或者说其他操作不影响该值 它只是作用初始化的时候 使用了浅拷贝–改变了初始值 会改变初始值(selectList1) 都指向同一个地址 const selectList1 { title: 大大, value: 1 };con…...

赛宁网安多领域亮相第三届网络空间内生安全发展大会
2023年12月8日,第三届网络空间内生安全发展大会在宁开幕。两院院士、杰出专家学者和知名企业家相聚南京,围绕数字经济新生态、网络安全新范式进行广泛研讨,为筑牢数字安全底座贡献智慧和力量。 大会围绕“一会、一赛、一展”举办了丰富多彩的…...
LintCode 123 · Word Search (DFS字符处理经典题!)
123 Word Search Algorithms Medium Description Given a 2D board and a string word, find if the string word exists in the grid. The string word can be constructed from letters of sequentially adjacent cell, where “adjacent” cells are those horizontally o…...

SpringCloud面试题——Sentinel
一:什么是Sentinel? Sentinel是一个面向分布式架构的轻量级服务保护框架,实现服务降级、服务熔断、服务限流等功能 二:什么是服务降级? 比如当某个服务繁忙,不能让客户端的请求一直等待,应该立刻返回给客户端一个备…...

【精选】 VulnHub (超详细解题过程)
🍬 博主介绍👨🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 🎉点赞➕评论➕收藏…...

数据结构与算法-Rust 版读书笔记-2线性数据结构-队列
数据结构与算法-Rust 版读书笔记-2线性数据结构-队列 1、队列:先进先出 队列是项的有序集合,其中,添加新项的一端称为队尾,移除项的另一端称为队首。一个元素在从队尾进入队列后,就会一直向队首移动,直到…...
Android Kotlin Viewbinding封装
目录 Viewbinding配置 Activity封装 Activity使用 Fragment封装 Fragment使用 Dialog封装 Dialog使用 Viewbinding配置 android { viewBinding { enabled true } } Activity封装 import android.os.Bundle import android.view.LayoutInflater import androidx.ap…...

Flutter:web项目跨域问题解决
前后端解决系列 文章目录 一、Flutter web客户端解决本地环境调试跨域问题二、Flutter web客户端解决线上环境跨域问题 一、Flutter web客户端解决本地环境调试跨域问题 就一句命令【--web-browser-flag "--disable-web-security"】,用来屏蔽浏览器域名请…...
汽车标定技术(十二)--A2L文件生成的方法
目录 1.工具生成 1.1 CANape/ASAP2 Studio 1.2 ASAP2ToolKit 1.3 Matlab/Simulink 2.手写A2L要点 3.小结 A2L文件的制作一直以来是一个很少有人关注的方向,不管是标定工程师还是Slave协议栈的开...

《PySpark大数据分析实战》-03.了解Hive
📋 博主简介 💖 作者简介:大家好,我是wux_labs。😜 热衷于各种主流技术,热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员(PCTA)、TiDB数据库专家(PCTP…...

经验分享|MySQL分区实战(RANGE)
概述 分区概述 在 MySQL 中, InnoDB存储引擎长期以来一直支持表空间的概念。在 MySQL 8.0 中,同一个分区表的所有分区必须使用相同的存储引擎。但是,也可以为同一 MySQL 服务器甚至同一数据库中的不同分区表使用不同的存储引擎。 通俗地讲…...

Arrays.asList() 和 Collections.singletonList()
Arrays.asList() 和 Collections.singletonList() 概述 List 是我们使用Java时常用的集合类型。众所周知,我们可以轻松地在一行中初始化列表。例如,当我们想要初始化一个只有一个元素的List时,我们可以使用Arrays.asList(&#…...

Firmware Analysis Plus (Fap)固件模拟安装教程(最新)
最近在搞IoT的研究,但是难在设备比较难弄,只有固件,而没有设备,买吧,又太费钱,不划算。好在有很多项目可以在模拟环境中运行固件。但是几乎没有一个平台能够模拟所有硬件设备。IoT产品的架构也不尽相同。 …...

使用包、Crate 和模块管理项目(上)
目录 1、包和Crate 2、定义模块来控制作用域与私有性 2.1 在模块中对相关代码进行分组 3、引用模块项目的路径 3.1 使用 pub 关键字暴露路径 二进制和库 crate 包的最佳实践 3.2 super 开始的相对路径 3.3 创建公有的结构体和枚举 Rust 有许多功能可以让你管理代码的组…...
【Kotlin】
Lambda 就是一小段可以作为参数传递的代码。 因为正常情况下,我们向某个函数传参时只能传入变量,而借助Lambda 却允许传入一小段代码。 Lambda 表达式的语法结构: {参数名1: 参数类型, 参数名2: 参数类型 -> 函数体}首先,最外…...

JavaDay17
创建不可变集合 import java.util.Iterator; import java.util.List;public class Test {public static void main(String[] args) {/*创建不可变的List集合* "张三" "李四" "王五" "赵六*///一旦创建之后 是无法进行修改的 在下面的代码…...

Python爬取酷我音乐
🎈 博主:一只程序猿子 🎈 博客主页:一只程序猿子 博客主页 🎈 个人介绍:爱好(bushi)编程! 🎈 创作不易:喜欢的话麻烦您点个👍和⭐! 🎈…...

华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...

测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分
一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计,提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合:各模块职责清晰,便于独立开发…...
Rapidio门铃消息FIFO溢出机制
关于RapidIO门铃消息FIFO的溢出机制及其与中断抖动的关系,以下是深入解析: 门铃FIFO溢出的本质 在RapidIO系统中,门铃消息FIFO是硬件控制器内部的缓冲区,用于临时存储接收到的门铃消息(Doorbell Message)。…...