电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術(shù)文章
文章詳情頁

Java ThreadLocal的使用詳解

瀏覽:2日期:2022-08-12 15:56:53
目錄1. 應(yīng)用場景1.1. 保障線程安全1.2. 顯示傳遞參數(shù)2. 實現(xiàn)原理3. 注意事項

ThreadLocal是線程私有的局部變量存儲容器,可以理解成每個線程都有自己專屬的存儲容器,用來存儲線程私有變量。ThreadLocal 在日常開發(fā)框架中應(yīng)用廣泛,但用不好也會出現(xiàn)各種問題,本文就此講解一下。

1. 應(yīng)用場景

ThreadLocal 的常見應(yīng)用場景有兩種:

多線程并發(fā)場景中,用來保障線程安全。 處理較為復(fù)雜的業(yè)務(wù)時,使用ThreadLocal代替參數(shù)的顯示傳遞。 1.1. 保障線程安全

多線程訪問同一個共享變量的時候容易出現(xiàn)并發(fā)問題,特別是多個線程對一個變量進行寫入的時候,為了保證線程安全,一般使用者在訪問共享變量的時候需要進行額外的同步措施才能保證線程安全性,如:synchronized、Lock之類的鎖。

ThreadLocal是除了加鎖這種同步方式之外的一種,規(guī)避多線程訪問出現(xiàn)線程不安全的方法。當(dāng)我們在創(chuàng)建一個變量后,如果每個線程對其進行訪問的時候訪問的都是線程自己的變量,這樣就不會存在線程不安全問題。

ThreadLocal是JDK包提供的,它提供線程本地變量,如果創(chuàng)建一個ThreadLocal變量,那么訪問這個變量的每個線程都會有這個變量的一個副本,在實際多線程操作的時候,操作的是自己本地內(nèi)存中的變量,從而規(guī)避了線程安全問題。

1.2. 顯示傳遞參數(shù)

這里舉幾個例子:

示例1:獲取接口的當(dāng)前請求用戶在后臺接口業(yè)務(wù)邏輯的全過程中,如果需要在多個地方獲取當(dāng)前請求用戶的信息。通常的一種做法就是:在接口請求時,通過過濾器、攔截器、AOP等方式,從session或token中獲取當(dāng)前用戶信息,存入ThreadLocal中。

在整個接口處理過程中,如果沒有另外創(chuàng)建線程,都可以直接從ThreadLocal變量中獲取當(dāng)前用戶,而無需再從Session、token中驗證和獲取用戶。這種方案設(shè)計不僅提高性能,最重要的是將原本復(fù)雜的邏輯和代碼實現(xiàn),變得簡潔明了。例如下面的這個例子:

(1)定義ThreadLocal變量:UserProfileThread.java

public class UserProfileThread { private static ThreadLocal<UserProfile> USER_PROFILE_TL =new ThreadLocal<>(); public static void setUserProfile(UserProfile userProfile){USER_PROFILE_TL.set(userProfile); } public static UserProfile getUserProfile() {return USER_PROFILE_TL.get(); } public static String getCurrentUser() {return Optional.ofNullable(USER_PROFILE_TL.get()).map(UserProfile::getUid).orElse(UserProfile.ANONYMOUS_USER); }}

(2)在過濾器中設(shè)置變量值:

@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {UserProfile userProfile = null;// ... 驗證和獲取用戶信息 userProfileUserProfileThread.setUserProfile(userProfile);filterChain.doFilter(servletRequest, servletResponse); }

(3)獲取當(dāng)前用戶信息

//獲取當(dāng)前用戶String uid=UserProfileThread.getCurrentUser();//獲取當(dāng)前用戶對象UserProfile user=UserProfileThread.getUserProfile();

示例2:spring框架中保證數(shù)據(jù)庫事務(wù)在同一個連接下執(zhí)行

要想實現(xiàn)jdbc事務(wù), 就必須是在同一個連接對象中操作,多個連接下事務(wù)就會不可控,需要借助分布式事務(wù)完成。那spring框架如何保證數(shù)據(jù)庫事務(wù)在同一個連接下執(zhí)行的呢?

DataSourceTransactionManager 是spring的數(shù)據(jù)源事務(wù)管理器,它會在你調(diào)用getConnection()的時候從數(shù)據(jù)庫連接池中獲取一個connection, 然后將其與ThreadLocal綁定,事務(wù)完成后解除綁定。這樣就保證了事務(wù)在同一連接下完成。

2. 實現(xiàn)原理

ThreadLocal類提供set/get方法存儲和獲取value值,但實際上ThreadLocal類并不存儲value值,真正存儲是靠ThreadLocalMap這個類。

每個線程實例都對應(yīng)一個TheadLocalMap實例,我們可以在同一個線程里實例化很多個ThreadLocal來存儲很多種類型的值,這些ThreadLocal實例分別作為key,對應(yīng)各自的value,最終存儲在Entry table數(shù)組中。我們看看ThreadLocal的set方法:

public class ThreadLocal<T> { public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) map.set(this, value);else createMap(t, value); } ThreadLocalMap getMap(Thread t) {return t.threadLocals; } void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue); } // 省略其他方法}

set的邏輯比較簡單,就是獲取當(dāng)前線程的ThreadLocalMap,然后往map里添加KV,K是當(dāng)前ThreadLocal實例,V是我們傳入的value。這里需要注意一下,map的獲取是需要從Thread類對象里面取,看一下Thread類的定義。

public class Thread implements Runnable { ThreadLocal.ThreadLocalMap threadLocals = null; //省略其他}

Thread類維護了一個ThreadLocalMap的變量引用。

因此,我們可以得出如下結(jié)論:

每個線程是一個Thread實例,其內(nèi)部維護一個threadLocals的實例成員,其類型是ThreadLocal.ThreadLocalMap。 ThreadLocal本身并不是一個容器,我們存取的value實際上存儲在ThreadLocalMap中,ThreadLocal只是作為TheadLocalMap的key。 3. 注意事項

ThreadLocal實例有提供remove()方法,用于回收對象,清除對應(yīng)的內(nèi)存占用。這個方法通常容易被忽略,而導(dǎo)致出現(xiàn)了各種問題。如下面幾種:

線程復(fù)用:在“獲取接口的當(dāng)前請求用戶”的例子中,Tomcat中是通過線程池來處理用戶請求的,而線程池中線程是復(fù)用的。肯定會出現(xiàn)一個線程前后被不同用戶的接口請求復(fù)用的情況,因此需要對用過的ThreaLocal變量進行覆蓋或清除。 內(nèi)存溢出:由于ThreadLocalMap的生命周期跟Thread一樣長,如果創(chuàng)建的ThreadLocal變量很多,即對應(yīng)的key占用的內(nèi)存很大,但卻沒有手動刪除,到了一定程度就會導(dǎo)致內(nèi)存泄漏。

以上就是Java ThreadLocal的使用詳解的詳細內(nèi)容,更多關(guān)于Java ThreadLocal的使用的資料請關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: Java
相關(guān)文章:
主站蜘蛛池模板: 定制/定做冲锋衣厂家/公司-订做/订制冲锋衣价格/费用-北京圣达信 | 济南玻璃安装_济南玻璃门_济南感应门_济南玻璃隔断_济南玻璃门维修_济南镜片安装_济南肯德基门_济南高隔间-济南凯轩鹏宇玻璃有限公司 | 板框压滤机-隔膜压滤机配件生产厂家-陕西华星佳洋装备制造有限公司 | 食药成分检测_调料配方还原_洗涤剂化学成分分析_饲料_百检信息科技有限公司 | 武汉创亿电气设备有限公司_电力检测设备生产厂家 | 依维柯自动挡房车,自行式国产改装房车,小型房车价格,中国十大房车品牌_南京拓锐斯特房车 - 南京拓锐斯特房车 | 飞行者联盟-飞机模拟机_无人机_低空经济_航空技术交流平台 | 玉米加工设备,玉米深加工机械,玉米糁加工设备.玉米脱皮制糁机 华豫万通粮机 | 好杂志网-首页 | 带式过滤机厂家_价格_型号规格参数-江西核威环保科技有限公司 | 曙光腾达官网-天津脚手架租赁-木板架出租-移动门式脚手架租赁「免费搭设」 | 北京印刷厂_北京印刷_北京印刷公司_北京印刷厂家_北京东爵盛世印刷有限公司 | 上海璟文空运首页_一级航空货运代理公司_机场快递当日达 | 手持式3d激光扫描仪-便携式三维立体扫描仪-北京福禄克斯 | 小威小说网 - 新小威小说网 - 小威小说网小说搜索引擎 | IHDW_TOSOKU_NEMICON_EHDW系列电子手轮,HC1系列电子手轮-上海莆林电子设备有限公司 | 通风天窗,通风气楼,屋顶通风天窗,屋顶通风天窗公司 | 医疗仪器模块 健康一体机 多参数监护仪 智慧医疗仪器方案定制 血氧监护 心电监护 -朗锐慧康 | 千淘酒店差旅平台-中国第一家针对TMC行业的酒店资源供应平台 | 深圳湾1号房价_深圳湾1号二手房源 | 铣刨料沥青破碎机-沥青再生料设备-RAP热再生混合料破碎筛分设备 -江苏锡宝重工 | 西门子代理商_西门子变频器总代理-翰粤百科 | 铝镁锰板_铝镁锰合金板_铝镁锰板厂家_铝镁锰金属屋面板_安徽建科 | 手持式线材张力计-套帽式风量罩-深圳市欧亚精密仪器有限公司 | 武汉印刷厂-不干胶标签印刷厂-武汉不干胶印刷-武汉标签印刷厂-武汉标签制作 - 善进特种标签印刷厂 | 老城街小面官网_正宗重庆小面加盟技术培训_特色面馆加盟|牛肉拉面|招商加盟代理费用多少钱 | led全彩屏-室内|学校|展厅|p3|户外|会议室|圆柱|p2.5LED显示屏-LED显示屏价格-LED互动地砖屏_蕙宇屏科技 | 好物生环保网、环保论坛 - 环保人的学习交流平台 | 炉门刀边腹板,焦化设备配件,焦化焦炉设备_沧州瑞创机械制造有限公司 | 智慧钢琴-电钢琴-便携钢琴-数码钢琴-深圳市特伦斯乐器有限公司 | 泰来华顿液氮罐,美国MVE液氮罐,自增压液氮罐,定制液氮生物容器,进口杜瓦瓶-上海京灿精密机械有限公司 | TPE塑胶原料-PPA|杜邦pom工程塑料、PPSU|PCTG材料、PC/PBT价格-悦诚塑胶 | 石家庄救护车出租_重症转院_跨省跨境医疗转送_活动赛事医疗保障_康复出院_放弃治疗_腾康26年医疗护送转诊团队 | 铝箔-铝板-花纹铝板-铝型材-铝棒管-上海百亚金属材料有限公司 | 螺杆式冷水机-低温冷水机厂家-冷冻机-风冷式-水冷式冷水机-上海祝松机械有限公司 | 新密高铝耐火砖,轻质保温砖价格,浇注料厂家直销-郑州荣盛窑炉耐火材料有限公司 | 线材成型机,线材折弯机,线材成型机厂家,贝朗自动化设备有限公司1 | 富森高压水枪-柴油驱动-养殖场高压清洗机-山东龙腾环保科技有限公司 | 玻璃钢格栅盖板|玻璃钢盖板|玻璃钢格栅板|树篦子-长沙川皖玻璃钢制品有限公司 | 十二星座查询(性格特点分析、星座运势解读) - 玄米星座网 | 冷轧机|两肋冷轧机|扁钢冷轧机|倒立式拉丝机|钢筋拔丝机|收线机-巩义市华瑞重工机械制造有限公司 |