Java的ThreadLocal

ThreadLocal

ThreadLocal 是 Java 中一个非常有用的类,它允许你创建线程局部变量。线程局部变量是指每个线程都有自己独立的变量副本,互不干扰。ThreadLocal 主要用于解决多线程环境下共享数据的线程安全性问题。

基本用法

创建 ThreadLocal 变量

ThreadLocal<Integer> threadLocalVariable = new ThreadLocal<>();

设置和获取线程局部变量:

threadLocalVariable.set(42); // 设置线程局部变量的值
int value = threadLocalVariable.get(); // 获取线程局部变量的值

初始值:
你可以通过覆盖 ThreadLocal 的 initialValue 方法来指定线程局部变量的初始值。例如:

ThreadLocal<Integer> threadLocalVariable = ThreadLocal.withInitial(() -> 0);

注意事项:
使用 ThreadLocal 时要小心内存泄漏,确保在不需要使用线程局部变量时及时清理。
在使用线程池时,注意线程复用可能导致线程局部变量的状态被共享。
ThreadLocal 是一个有助于在多线程应用程序中维护线程局部状态的重要工具,但它需要谨慎使用,以避免潜在的问题。确保理解其工作原理,并在需要的情况下适当使用它,可以提高多线程程序的性能和可维护性。

ThreadLocal理解

ThreadLocal是一个将在多线程中为每一个线程创建单独的变量副本的类; 当使用ThreadLocal来维护变量时, ThreadLocal会为每个线程创建单独的变量副本, 避免因多线程操作共享变量而导致的数据不一致的情况。#
最多的是session管理和数据库链接管理,这里以数据访问为例帮助你理解ThreadLocal:

class ConnectionManager {private static Connection connect = null;public static Connection openConnection() {if (connect == null) {connect = DriverManager.getConnection();}return connect;}public static void closeConnection() {if (connect != null)connect.close();}
}

据库管理类在单线程使用是没有任何问题的,在多线程中使用会存在线程安全问题:第一,这里面的2个方法都没有进行同步,很可能在openConnection方法中会多次创建connect;第二,多次进行closeConnection可能会导致空指针异常问题;第三,由于connect是共享变量,那么必然在调用connect的地方需要使用到同步来保障线程安全,因为很可能一个线程在使用connect进行数据库操作,而另外一个线程调用closeConnection关闭链接。

为了解决上述线程安全的问题,第一考虑:互斥同步
你可能会说,将这段代码的两个方法进行同步处理,并且在调用connect的地方需要进行同步处理,比如用Synchronized或者ReentrantLock互斥锁。
这里再抛出一个问题:这地方到底需不需要将connect变量进行共享?
事实上,是不需要的。假如每个线程中都有一个connect变量,各个线程之间对connect变量的访问实际上是没有依赖关系的,即一个线程不需要关心其他线程是否对这个connect进行了修改的。即改后的代码可以这样:

class ConnectionManager {private Connection connect = null;public Connection openConnection() {if (connect == null) {connect = DriverManager.getConnection();}return connect;}public void closeConnection() {if (connect != null)connect.close();}
}class Dao {public void insert() {ConnectionManager connectionManager = new ConnectionManager();Connection connection = connectionManager.openConnection();// 使用connection进行操作connectionManager.closeConnection();}
}

这样处理确实也没有任何问题,由于每次都是在方法内部创建的连接,那么线程之间自然不存在线程安全问题。但是这样会有一个致命的影响:导致服务器压力非常大,并且严重影响程序执行性能。由于在方法中需要频繁地开启和关闭数据库连接,这样不仅严重影响程序执行效率,还可能导致服务器压力巨大。
这时候ThreadLocal登场了那么这种情况下使用ThreadLocal是再适合不过的了,因为ThreadLocal在每个线程中对该变量会创建一个副本,即每个线程内部都会有一个该变量,且在线程内部任何地方都可以使用,线程之间互不影响,这样一来就不存在线程安全问题,也不会严重影响程序执行性能。下面就是网上出现最多的例子:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;public class ConnectionManager {private static final ThreadLocal<Connection> dbConnectionLocal = new ThreadLocal<Connection>() {@Overrideprotected Connection initialValue() {try {return DriverManager.getConnection("", "", "");} catch (SQLException e) {e.printStackTrace();}return null;}};public Connection getConnection() {return dbConnectionLocal.get();}
}

ThreadLocal原理

如何实现线程隔离

主要是用到了Thread对象中的一个ThreadLocalMap类型的变量threadLocals, 负责存储当前线程的关于Connection的对象, dbConnectionLocal(以上述例子中为例) 这个变量为Key, 以新建的Connection对象为Value; 这样的话, 线程第一次读取的时候如果不存在就会调用ThreadLocal的initialValue方法创建一个Connection对象并且返回;
具体关于为线程分配变量副本的代码如下:

public T get() {Thread t = Thread.currentThread();ThreadLocalMap threadLocals = getMap(t);if (threadLocals != null) {ThreadLocalMap.Entry e = threadLocals.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue();
}

https://pdai.tech/md/java/thread/java-thread-x-threadlocal.html

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

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

相关文章

开源云原生网关Linux Traefik本地部署结合内网穿透远程访问

文章目录 前言1. Docker 部署 Trfɪk2. 本地访问traefik测试3. Linux 安装cpolar4. 配置Traefik公网访问地址5. 公网远程访问Traefik6. 固定Traefik公网地址 前言 Trfɪk 是一个云原生的新型的 HTTP 反向代理、负载均衡软件&#xff0c;能轻易的部署微服务。它支持多种后端 (D…

一文带你了解UI自动化测试框架

PythonSeleniumUnittestDdtHTMLReport分布式数据驱动自动化测试框架结构 1、Business&#xff1a;公共业务模块&#xff0c;如登录模块&#xff0c;可以把登录模块进行封装供调用 ------login_business.py from Page_Object.Common_Page.login_page import Login_Page from H…

六. 函数

基本使用 ts与js一样拥有具名函数和匿名函数两种函数类型。但是ts的函数需要提前定义好参数类型以及函数的返回值类型。 具名函数 function add(num1: number, num2: number):number {return num1 num2 }匿名函数 匿名函数的定义相对麻烦&#xff0c;我们需要提前定义函数的…

ubuntu22 安装 cuda12.0

本文是先安装显卡驱动后进行的操作 查看显卡驱动支持CUDA的最新版本12.0 nvidia-smi 检查gcc版本 gcc -v 查看系统支持的gcc版本 https://docs.nvidia.com/cuda/cuda-installation-guide-linux/index.html 选择对应的安装cuda命令 https://developer.nvidia.com/cuda-too…

工业级路由器在货运物流仓储管理中的应用

工业级路由器在货运物流仓储管理中扮演着重要的角色&#xff0c;为整个物流系统提供了稳定可靠的网络连接和数据传输支持。下面将从以下几个方面介绍工业级路由器在货运物流仓储管理中的应用。 实时监控和追踪&#xff1a;工业级路由器通过与各种传感器、监控设备和物联网设备的…

【论文阅读】深度学习方法在数字岩石技术中的应用进展

【论文名称】Advances in the application of deep learning methods to digital rock technology 深度学习方法在数字岩石技术中的应用进展 【论文来源】EI检索 【作者单位】长江大学地球物理与油气资源学院、加拿大阿尔伯塔大学土木与环境工程系、东北石油大学地球科学学院、…

【剑指offer|图解|数组】寻找文件副本 + 螺旋遍历二维数组

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;数据结构、剑指offer每日一练 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. ⛳️寻找文件副本(题目难度&#xff1a;简单)1.1 题目1.2 示例1.3 限制1.4 解题思路一c代…

微信网页授权步骤说明

总览 引导用户进入授权页面同意授权&#xff0c;获取code通过code换取网页授权access_token&#xff08;与基础支持中的access_token不同&#xff09;如果需要&#xff0c;开发者可以刷新网页授权access_token&#xff0c;避免过期&#xff08;一般不需要&#xff09;通过网页…

高翔《自动驾驶与机器人中的SLAM技术》第九、十章载入静态地图完成点云匹配重定位

修改mapping.yaml文件中bag_path&#xff1a; 完成之后会产生一系列的点云文件以及Keyframe.txt文件&#xff1a; ./bin/run_frontend --config_yaml ./config/mapping 生成拼接的点云地图map.pcd文件 &#xff1a; ./bin/dump_map --pose_sourcelidar 。、 完成第一次优…

低代码开发:属于“美味膳食”还是“垃圾食品”

目录 引言低代码是什么&#xff1f;低代码的优点使用挑战未来展望最后 引言 随着数字化转型的迅猛发展&#xff0c;低代码开发平台逐渐成为了企业和开发者的关注焦点&#xff0c;尤其是前两年低代码的迅速火爆&#xff0c;来势汹汹&#xff0c;号称要让大部分程序员下岗的功能…

html2canvas库——前端实现基于DOM的截图

官网&#xff1a; html2canvas - Screenshots with JavaScript Github: https://github.com/niklasvh/html2canvas 资料&#xff1a; html2canvas使用教程-CSDN博客&#xff1a;https://blog.csdn.net/weixin_45917647/article/details/126250424 html2canvas实现浏览器…

双指针算法(一)

目录 移动零 复写零 快乐数 盛水最多的容器 双指针与单调性结合 有效三角形的个数 查找总价格为目标值的两个商品 两数之和 Ⅱ - 输入有序数组 双指针算法是通过定义两个指针不断单向移动来解决问题的一种算法。但双指针算法&#xff0c;是一个抽象的思想概念&#xf…

dockerfile,Docker镜像的创建

dockerfile&#xff1a;创建镜像&#xff0c;创建自定义的镜像。包括配置文件&#xff0c;挂载点&#xff0c;对外暴露的端口。设置环境变量。 docker的创建镜像的方式&#xff1a; 1、基于已有镜像进行创建。根据官方提供的镜像源&#xff0c;创建镜像&#xff0c;然后拉起容…

leetcode算法题:岛屿数量

leetcode算法题200 链接&#xff1a;https://leetcode.cn/problems/number-of-islands 题目 你一个由 ‘1’&#xff08;陆地&#xff09;和 ‘0’&#xff08;水&#xff09;组成的的二维网格&#xff0c;请你计算网格中岛屿的数量。 岛屿总是被水包围&#xff0c;并且每座岛…

Linux主机自动注册NPS客户端(脚本化)

参考官方对API使用方法的定义&#xff1a;https://ehang-io.github.io/nps/#/ 1、首先必须要在配置文件中开启 auth_key 并配置一个合适的密钥 2、修改脚本中的可变量参数&#xff0c;以适配自己的环境 #!/bin/bash # 脚本使用说明&#xff1a;# 脚本名称&#xff1a;npc_cr…

+0和不+0的性能差异

前几日&#xff0c;有群友转发了某位技术大佬的weibo。并在群里询问如下两个函数哪个执行的速度比较快&#xff08;weibo内容&#xff09;。 func g(n int, ch chan<- int) {r : 0for i : 0; i < n; i {r i}ch <- r 0 }func f(n int, ch chan<- int) {r : 0for …

基于Microchip 光伏逆变器方案

小编杂谈新能源已经完成了至少5期的博文了&#xff0c;Boss告诉小编&#xff0c;如果还不介绍我们的产品和方案&#xff0c;黄花菜都凉了&#xff0c;所以小编这期博文就重点介绍一下Microchip在储能上的产品介绍&#xff0c;重点聊聊Microchip储能中使用的光伏逆变器的解决方案…

期末数组函数加强练习

前言&#xff1a;由于时间问题&#xff0c;部分题解取自网友&#xff0c;但都是做过的好题。 对于有些用c实现的题目&#xff0c;可以转化成c实现&#xff0c;cin看成c的读入&#xff0c;可以用scanf&#xff0c;输出cout看作printf&#xff0c;endl即换行符 开胃菜&#xff…

PHP和go搭建分布式

分布式系统是指由多台计算机组成的网络系统&#xff0c;这些计算机通过网络进行通信和协作&#xff0c;共同完成一个任务。在分布式系统中&#xff0c;通信和数据共享是非常重要的&#xff0c;因此需要使用一些特定的技术和工具进行构建和管理。 PHP和Go都是非常流行的编程语言…

ES6原生音乐播放器(有接口)

视频展示 ES6音乐播放器 项目介绍 GutHub地址&#xff1a;GitHub - baozixiangqianchong/ES6_MusicPlayer: 音乐播放器 ES6_MusicPlayer 是基于JavaScriptES6Ajax等通过原生构建的项目。能够充分锻炼JS能力。 本项目有主页、详情页、歌单页面三部分组成 ├── assets&…