深刻解析 volatile 关键字和线程本地存储ThreadLocal
1.volatile关键字在Java多线程编程中的重要性
在多线程编程中,volatile关键字扮演着至关重要的角色,它确保了变量在多个线程间的可见性,并且能防止指令重排序,从而达到线程安全的目的。
1.1 保证多线程环境下变量的可见性
在Java的并发编程中,线程间共享变量的更新可能不会立即对其他线程可见,这是因为线程可以把变量保留在局部内存中。而使用volatile声明的变量可以强制线程读写直接操作主内存,确保每个线程看到的变量是最新的值。
class SharedObject {volatile int sharedCounter;void increment() {sharedCounter++;}
}
1.2 禁止指令重排序
处理器为了提高程序运行效率,可能会对指令序进行优化,使得实际执行的顺序与代码编写的顺序不一致。对于单线程程序这通常不是问题,但在多线程中可能导致严重错误。volatile关键字可以禁止这种重排序,确保程序的执行顺序与代码的顺序一致。
1.3 volatile vs synchronized:使用场景与性能比较
volatile和synchronized都可以解决多线程中的数据同步问题,但volatile由于不会引起线程上下文的切换或调度,因此开销比synchronized小,适用于轻量级的同步需求,如状态标记。
class VolatileExample {volatile boolean isRunning = true;void run() {while (isRunning) {// ...}}
}
1.4 实例:使用volatile保证操作的原子性
虽然volatile可以保证变量的可见性,但它并不能保证复合操作(如i++)的原子性。在使用volatile时仍需注意,对于复合操作需要额外的同步策略。
2.在Java中实现线程间的数据共享
数据共享是多线程编程的核心问题之一,正确地在多个线程间共享数据是实现并发程序的关键步骤。
2.1 设计线程安全的共享数据类
线程安全的数据类通常包含了同步机制,以确保在任意时刻只有一个线程能够写入共享数据,同时可以由多个线程读取数据而不会发生冲突。
public class SafeSharedData {private int data;// 同步方法,保持方法原子性public synchronized void setData(int value) {this.data = value;}public synchronized int getData() {return data;}
}
2.2 通过内部类实现Runnable接口
您可以通过内部类来包装共享数据和它的操作,然后实现Runnable接口,使得线程能够操作同一个数据实例。
public class SharedDataWrapper implements Runnable {private SafeSharedData sharedData;public SharedDataWrapper(SafeSharedData data) {this.sharedData = data;}@Overridepublic void run() {// 使用sharedData的同步方法操作数据}
}
2.3 使用锁机制同步数据访问
ReentrantLock是一种广泛使用的锁机制,能够对数据访问进行精准的控制。这个锁支持锁重入,意味着可以在一个锁已经被获取的前提下,再次获取此锁不会产生死锁。
import java.util.concurrent.locks.ReentrantLock;
public class Counter {private final ReentrantLock lock = new ReentrantLock();private int count = 0;public void increment() {lock.lock(); // 获取锁try {count++;} finally {lock.unlock(); // 释放锁}}public int getCount() {lock.lock(); // 获取锁try {return count;} finally {lock.unlock(); // 释放锁}}
}
使用锁时,一定要在try-finally块中释放所持有的锁,以避免死锁或资源泄漏。
3.ThreadLocal的使用及其对多线程的影响
ThreadLocal是Java提供的一种线程局部存储机制,允许每个线程在其内部保存数据,而这些数据对其他线程是隔离的。
3.1 ThreadLocal简介及其工作原理
ThreadLocal通过提供线程内部的私有变量副本,来避免其它线程的干扰和冲突。
public class ThreadLocalExample {private ThreadLocal<Integer> threadLocalCount = new ThreadLocal<>();public void setThreadLocalCount(int value) {threadLocalCount.set(value);}public int getThreadLocalCount() {return threadLocalCount.get();}
}
3.1.1 ThreadLocal类与ThreadLocalMap关系
每个线程内部都有一个ThreadLocalMap,其键值对的键是ThreadLocal对象,而值则是线程内部想要存储的对象。
3.1.2 ThreadLocal与线程隔离性
ThreadLocal确保每一个线程都有一个独立的变量副本,它提供了一种将状态和数据从其它线程隔离开来的手段。
3.2 ThreadLocal在实际编程中的应用场景
ThreadLocal在很多编程场景中非常有用,尤其是与会话信息和用户身份认证有关的场景。
3.2.1 用户身份验证
在Web开发中,可以利用ThreadLocal存储用户登录信息,确保每个线程独立处理各自的用户数据。
3.2.2 数据库连接管理
ThreadLocal可以用于保持数据库连接,使得每个线程都拥有自己的数据库连接,从而提高数据库操作的效率。
3.2.3 会话信息控制
在HTTP服务中,ThreadLocal常用于存储会话信息,满足服务端处理需求。
3.3 实例:ThreadLocal在Web应用中的典型用法
以下是一个在Web应用中使用ThreadLocal来存储当前HTTP请求信息的例子。
public class WebUserContext {private static ThreadLocal<HttpServletRequest> userThreadLocal = new ThreadLocal<>();public static HttpServletRequest getRequest() {return userThreadLocal.get();}public static void setRequest(HttpServletRequest request) {userThreadLocal.set(request);}
}
在这个例子中,我们确保了每个线程只处理它自己的请求,通过存储在ThreadLocal变量中,可以在代码的任何部分方便地获取当前的HttpServletRequest
对象,而不用担心其他线程的交叉访问问题。
在这样的用例中,可以在Web请求的初始处理阶段设置ThreadLocal
,之后在整个请求处理过程中的任何地方获取这个信息。处理完请求后,很重要的一点是要清理掉ThreadLocal
存储的数据,避免内存泄漏。
例如,在一个Servlet过滤器中设定和清除ThreadLocal:
public class UserContextFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {try {WebUserContext.setRequest((HttpServletRequest) request);chain.doFilter(request, response);} finally {WebUserContext.setRequest(null); // 清理ThreadLocal中的数据}}
}
这样的做法可以在每个请求结束时自动清除ThreadLocal中的数据,这是一个良好的实践,帮助避免内存泄漏。
结合前面的章节内容,我们有了对Java多线程中变量使用机制更深入的理解,包括volatile确保变量的可见性和禁止指令重排序,以及如何安全高效地在多线程中共享数据。还有ThreadLocal的使用,它提供了一种保持线程内数据隔离的高效方法,在多线程编程中非常有用,特别是在处理一些线程安全的临时状况或为每个线程维护一个私有的状态。
相关文章:
深刻解析 volatile 关键字和线程本地存储ThreadLocal
1.volatile关键字在Java多线程编程中的重要性 在多线程编程中,volatile关键字扮演着至关重要的角色,它确保了变量在多个线程间的可见性,并且能防止指令重排序,从而达到线程安全的目的。 1.1 保证多线程环境下变量的可见性 在Ja…...

羧甲基纤维素钠(CMC-Na)市场规模不断增长 我国生产企业众多
羧甲基纤维素钠(CMC-Na)市场规模不断增长 我国生产企业众多 羧甲基纤维素钠(CMC-Na)又称CMC-钠,化学式为[C6H7O2(OH)2OCH2COONa]n,是一种离子型纤维素醚。CMC-Na外观呈白色颗粒状或纤…...
网红郭有才是怎么火起来的
网红郭有才的爆火主要归因于以下几个因素: 独特的个人魅力与风格:郭有才以其地道的乡土气息和个人的朴实无华赢得了观众的喜爱。他的视频内容展现了真实且接地气的生活场景,给人以亲切感。同时,他的幽默感也是吸引观众的一个重要因…...

小米8SE刷root(面具)
首先准备好一根数据线,一部小米8SE手机,和一台电脑 接下来需要的软件我会给出链接和使用方法,以及分享我遇到的困难和解决方案 下面操作不会的,可以参考这个博主的教程,我也是跟着这个教程刷好的 第一步解锁BL 开启开…...

如果创办Google
本文是一篇演讲稿,来自于《黑客与画家》一书的作者保罗*格雷厄姆,被称为硅谷创业之父。这是他为14至15岁的孩子们做的一次演讲,内容是关于如果他们将来想创立一家创业公司,现在应该做些什么。很多学校认为应该向学生们传授一些有关…...
邦芒职场:揭秘影响你职场收入的九大细节
在职场这个大舞台上,微小的细节往往能决定你收入的多少。以下九大细节,是你职场成功的关键,不容忽视。 1. 形象塑造 在这个注重第一印象的时代,良好的形象是你的第一张名片。精致的妆容、得体的着装,不仅能为你加分&a…...

Petalinux 制作ZYNQ镜像文件流程
1概述 在Zynq-7000 SoC中搭建运行Linux,嵌入式软件栈。 处理器系统引导是一个分两个阶段的过程。第一个阶段是一个内部 BootROM,它存储 stage-0 的引导代码。BootROM 在 CPU 0 上执行,CPU 1 执行等待事件(WFE)指令。…...

99%的人都不知道,微信才是真正的学习神器
微信,作为一款全球最受欢迎的社交应用之一,除了聊天、朋友圈、小程序等功能外,还有许多隐藏的学习功能,今天小编就给大家分享10个微信隐藏的学习功能,助您轻松成为学霸。 1、微信笔记 用过代办清单软件的朋友都知道&…...

加速模型训练 GPU cudnn
GPU的使用 在定义模型时,如果没有特定的GPU设置,会使用 torch.nn.DataParallel 将模型并行化,充分利用多GPU的性能,这在加速训练上有显著影响。 model torch.nn.DataParallel(model).cuda() cudnn 的配置: cudnn.…...

《python编程从入门到实践》day40
# 昨日知识点回顾 编辑条目及创建用户账户 暂没能解决bug: The view learning_logs.views.edit_entry didnt return an HttpResponse object. It returned None instead.# 今日知识点学习 19.2.5 注销 提供让用户注销的途径 1.在base.html中添加注销链接 …...
IO多路复用学习笔记
参考资料: 视频1 视频2(本人B站也有发布) 视频3 参考笔记 参考博客...
Ubuntu设置中文输入法教程
在Ubuntu中设置中文输入法非常简单,只需按照以下步骤操作即可。 打开“设置”菜单。在Ubuntu的左上角点击“活动”按钮,然后在弹出的菜单中选择“设置”图标。 进入“区域和语言”设置。在设置菜单中,找到并点击“区域和语言”选项。 添加中…...
机器学习之爬山算法(Hill Climbing Algorithm)
爬山算法(Hill Climbing Algorithm)是一种简单而常见的启发式搜索算法,通常用于解决优化问题。它的基本思想类似于登山过程中爬升到山顶的过程,即从一个起始点开始,不断尝试向邻近的点移动,直到找到一个局部最优解。 下面是爬山算法的基本工作流程: 初始化:选择一个初…...

LeetCode - 贪心算法 (Greedy Algorithm) 集合 [分配问题、区间问题]
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/139242199 贪心算法,是在每一步选择中,都采取当前状态下,最好或最优(即最有利)的选择&…...

Linux中ftp配置
一、ftp协议 1、端口 ftp默认使用20、21端口 20端口用于建立数据连接 21端口用于建立控制连接 2、ftp数据连接模式 主动模式:服务器主动发起数据连接 被动模式:服务器被动等待数据连接 二、ftp安装 yum install -y vsftpd #---下…...

BWVS 靶场测试
一、PHP弱类型 is_numeric() 输入:127.0.0.1/BWVS/bug/php/code.php # 1、源代码分析 如果num不是数字,那么就输出num,同时如果num1,就输出flag。即num要是字符串又要是数字 # 2、函数分析: is_numeric()函数&…...

c++ 里重解释转换之于引用 reinterpret_cast< long >
今天遇到了这一很新奇的写法。模糊中记得王老师也这么讲过。c 里四大转换。把数据重解释为原来数据的引用。虽然也可以直接定义对变量的引用。测试如下: 咱们从反汇编再了解下 c 编译器是怎么处理这种写法的: 谢谢...

JAVASE2
封装的步骤: 1、所有属性私有化,使用private关键字进行修饰,private表示私有的,修饰的所有数据只能在本类中访问 2、对外提供简单入口:比如说被private修饰的成员变量,在其他类中只能通过getXxx/setXxx方法…...

ora-00392 ora-00312错误处理
检查当前日志组状态 对日志组进行clear操作 重新开库无报错...
网页、h5默认滚动条样式重构
文章目录 前言一、使用步骤1、在想要滚动的元素上设置相应的css类名2.设置样式 总结 前言 此文章用于,让我自己快速设置 浏览器、h5 默认滚动条样式…… 一、使用步骤 1、在想要滚动的元素上设置相应的css类名 代码如下: <div class"list scro…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
连锁超市冷库节能解决方案:如何实现超市降本增效
在连锁超市冷库运营中,高能耗、设备损耗快、人工管理低效等问题长期困扰企业。御控冷库节能解决方案通过智能控制化霜、按需化霜、实时监控、故障诊断、自动预警、远程控制开关六大核心技术,实现年省电费15%-60%,且不改动原有装备、安装快捷、…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

云原生玩法三问:构建自定义开发环境
云原生玩法三问:构建自定义开发环境 引言 临时运维一个古董项目,无文档,无环境,无交接人,俗称三无。 运行设备的环境老,本地环境版本高,ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...