了解ThreadLocal背后的概念

介紹

我知道本地線程,但直到最近才真正使用過它。
因此,我開始深入研究該主題,因為我需要一種傳播某些用戶信息的簡便方法
通過Web應用程序的不同層,而無需更改每個調用方法的簽名。

小前提信息

線程是具有自己的調用棧的單個進程。在Java中,每個調用棧有一個線程,或者每個線程有一個調用棧。即使您沒有在程序中創建任何新線程,線程也可以在沒有您的程序的情況下運行最好的例子是當您僅通過main方法啟動一個簡單的Java程序時,您沒有隱式調用new Thread()。start(),而是JVM為您創建了一個主線程來運行main方法。

主線程是非常特殊的,因為它是所有其他線程都會從中生成的線程,
線程完成后,應用程序結束了它的生命周期。

在Web應用程序服務器中,通常會有一個線程池,因為要創建的線程類非常重。所有JEE服務器(Weblogic,Glassfish,JBoss等)都有一個自調整線程池,這意味著線程池會增加或減少需要的時間,因此不會在每個請求上創建線程,而現有的線程將被重用。

了解線程局部

為了更好地理解線程本地,我將展示一種自定義線程本地的非常簡單的實現。

package ccs.progest.javacodesamples.threadlocal.ex1;import java.util.HashMap;
import java.util.Map;public class CustomThreadLocal {private static Map threadMap = new HashMap();public static void add(Object object) {threadMap.put(Thread.currentThread(), object);}public static void remove(Object object) {threadMap.remove(Thread.currentThread());}public static Object get() {return threadMap.get(Thread.currentThread());}}

因此,您可以隨時在應用程序中調用CustomThreadLocal上的add方法, 它將把當前線程作為并將要與該線程關聯的對象作為值放入映射中 。 該對象可能是您希望從當前執行的線程中的任何位置訪問的對象,或者可能是您想要與該線程保持關聯并重復使用多次的昂貴對象。
您定義一個ThreadContext類,您在其中擁有要在線程內傳播的所有信息。

package ccs.progest.javacodesamples.threadlocal.ex1;public class ThreadContext {private String userId;private Long transactionId;public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public Long getTransactionId() {return transactionId;}public void setTransactionId(Long transactionId) {this.transactionId = transactionId;}public String toString() {return 'userId:' + userId + ',transactionId:' + transactionId;}}

現在是時候使用ThreadContext了。

我將啟動兩個線程,并在每個線程中添加一個新的ThreadContext實例,該實例將保存我想為每個線程傳播的信息。

package ccs.progest.javacodesamples.threadlocal.ex1;public class ThreadLocalMainSampleEx1 {public static void main(String[] args) {new Thread(new Runnable() {public void run() {ThreadContext threadContext = new ThreadContext();threadContext.setTransactionId(1l);threadContext.setUserId('User 1');CustomThreadLocal.add(threadContext);//here we call a method where the thread context is not passed as parameterPrintThreadContextValues.printThreadContextValues();}}).start();new Thread(new Runnable() {public void run() {ThreadContext threadContext = new ThreadContext();threadContext.setTransactionId(2l);threadContext.setUserId('User 2');CustomThreadLocal.add(threadContext);//here we call a method where the thread context is not passed as parameterPrintThreadContextValues.printThreadContextValues();}}).start();}
}

注意:
CustomThreadLocal.add(threadContext)是當前線程與ThreadContext實例相關聯的代碼行
您將看到執行此代碼,結果將是:

userId:User 1,transactionId:1
userId:User 2,transactionId:2

這是怎么可能的,因為我們沒有將ThreadContext,userId或trasactionId作為參數傳遞給printThreadContextValues?

package ccs.progest.javacodesamples.threadlocal.ex1;public class PrintThreadContextValues {public static void printThreadContextValues(){System.out.println(CustomThreadLocal.get());}
}

很簡單

從CustomThreadLocal的內部映射調用CustomThreadLocal.get()時,將檢索與當前線程關聯的對象。

現在,讓我們看看何時使用真正的ThreadLocal類的示例。 (上面的CustomThreadLocal類只是為了了解ThreadLocal類背后的原理,該原理非常快并以最佳方式使用內存)

package ccs.progest.javacodesamples.threadlocal.ex2;public class ThreadContext {private String userId;private Long transactionId;private static ThreadLocal threadLocal = new ThreadLocal(){@Overrideprotected ThreadContext initialValue() {return new ThreadContext();}};public static ThreadContext get() {return threadLocal.get();}public String getUserId() {return userId;}public void setUserId(String userId) {this.userId = userId;}public Long getTransactionId() {return transactionId;}public void setTransactionId(Long transactionId) {this.transactionId = transactionId;}public String toString() {return 'userId:' + userId + ',transactionId:' + transactionId;}
}

如javadoc所述:ThreadLocal實例通常是希望將狀態與線程關聯的類中的私有靜態字段。

package ccs.progest.javacodesamples.threadlocal.ex2;public class ThreadLocalMainSampleEx2 {public static void main(String[] args) {new Thread(new Runnable() {public void run() {ThreadContext threadContext = ThreadContext.get();threadContext.setTransactionId(1l);threadContext.setUserId('User 1');//here we call a method where the thread context is not passed as parameterPrintThreadContextValues.printThreadContextValues();}}).start();new Thread(new Runnable() {public void run() {ThreadContext threadContext = ThreadContext.get();threadContext.setTransactionId(2l);threadContext.setUserId('User 2');//here we call a method where the thread context is not passed as parameterPrintThreadContextValues.printThreadContextValues();}}).start();}
}

調用get時 ,新的ThreadContext實例與當前線程關聯,然后將所需的值設置為ThreadContext實例。

如您所見,結果與第一組樣本相同。

userId:User 1,transactionId:1
userId:User 2,transactionId:2

(這可能是相反的順序,所以不要擔心如果您首先看到“用戶2”?)

package ccs.progest.javacodesamples.threadlocal.ex2;public class PrintThreadContextValues {public static void printThreadContextValues(){System.out.println(ThreadContext.get());}
}

ThreadLocal的另一種非常有用的用法是當您有一個非常昂貴的對象的非線程安全實例時的情況。我發現的大多數極性示例是使用SimpleDateFormat(但很快我將提供另一個使用Webservices端口的示例)

package ccs.progest.javacodesamples.threadlocal.ex4;import java.text.SimpleDateFormat;
import java.util.Date;public class ThreadLocalDateFormat {// SimpleDateFormat is not thread-safe, so each thread will have oneprivate static final ThreadLocal formatter = new ThreadLocal() {@Overrideprotected SimpleDateFormat initialValue() {return new SimpleDateFormat('MM/dd/yyyy');}};public String formatIt(Date date) {return formatter.get().format(date);}
}

結論:

線程局部變量有很多用途,這里僅描述兩種:(我認為使用最多的)

  • 真正的每線程上下文,例如用戶ID或事務ID。
  • 每線程實例以提高性能。

參考: Java代碼樣本博客中的JCG合作伙伴 Cristian Chiovari 了解了ThreadLocal的概念 。


翻譯自: https://www.javacodegeeks.com/2012/07/understanding-concept-behind.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/371777.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/371777.shtml
英文地址,請注明出處:http://en.pswp.cn/news/371777.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python加密模塊教程_Python加密模塊的hashlib,hmac模塊使用解析

這篇文章主要介紹了Python加密模塊的hashlib,hmac模塊使用解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下在寫搬磚腳本中,碰到一個加密的信號標簽文件無法運行。import hashlibimport timem ha…

DAO層–救援通用

泛型可以是使用編譯時驗證(類型安全性)的功能來創建可重用代碼的強大工具。 不幸的是,我感到主流開發人員仍然對此感到恐懼。 但是,比喻海格的蜘蛛,我會說泛型是被嚴重誤解的生物……:-) 我希望以下示例可以證明它們…

ThreadLocal詳解(實現多線程同步訪問變量)

ThreadLocal翻譯成中文比較準確的叫法應該是:線程局部變量。 這個玩意有什么用處,或者說為什么要有這么一個東東?先解釋一下,在并發編程的時候,成員變量如果不做任何處理其實是線程不安全的,各個線程都 在操…

SCREEN屏幕編程時候必須保證SCREN中詞典的字段格式必須和數據表中字段的類型長度一致!...

此時任意操作都會出現如下問題 /h調試 回車調試被激活任意操作 執行到第23行時候報錯“請輸入一個數值”,檢查數據表中字段參考數據元素以及對應的域均是char類型,此時檢查screen屏幕設置字段類型,/n退出程序 重新進入程序 單擊 點擊屏幕9000…

mysql 阿里云 版本_關于阿里云centos版本,mysql5.7的一些注意事項

1.阿里云進去mysql是默認已經安裝好了的,只需要修改root用戶的密碼。關于修改密碼:1)登陸阿里云,進入root目錄,會有mysql的.sh文件,可以通過運行該文件得到初始密碼。此時用初始密碼登陸mysql,use mysql 切…

JAXB –不需要注釋

似乎存在一個誤解,認為在模型上需要使用批注才能使用JAXB(JSR-222)實現。 事實是,JAXB是例外配置,因此僅當您要覆蓋默認行為時才需要注釋。 在此示例中,我將演示如何在不提供任何元數據的情況下使用JAXB。 …

zabbix 3.0.3 (nginx)安裝過程中的問題排錯記錄

特殊注明:安裝zabbix 2.4.8和2.4.6遇到2個問題,如下:找了很多解決辦法,實在無解,只能換版本,嘗試換(2.2.2正常 | 3.0.3正常)都正常,最后決定換3.0.31、Error connecting …

安裝mysql5.7.24rpm_centos7安裝mysql-5.7.24(rpm安裝)

關于mysql的4個rpm包node[rootelk-200 ~]# ls mysql/ -lhtotal 192M-rw-r--r-- 1 root root 25M Aug 26 12:38 mysql-community-client-5.7.24-1.el7.x86_64.rpm-rw-r--r-- 1 root root 275K Aug 26 12:38 mysql-community-common-5.7.24-1.el7.x86_64.rpm-rw-r--r-- 1 root ro…

Java鎖實現

我們都使用第三方庫作為開發的正常部分。 通常,我們無法控制其內部。 JDK隨附的庫是一個典型示例。 這些庫中的許多庫都使用鎖來管理競爭。 JDK鎖具有兩種實現。 人們使用原子CAS樣式指令來管理索賠過程。 CAS指令往往是最昂貴的CPU指令類型,并且在x86上…

一鍵生成APP官網

只需要輸入蘋果下載地址,安卓市場下載地址,或者內測下載地址,就能一鍵生成APP的官網,方便在網上推廣。 好推APP官網 www.hotapp.cn/app 轉載于:https://www.cnblogs.com/likwo/p/6223889.html

python 字符ab+字符c 2_“ab”+”c”*2 結果是: (1.3分)_學小易找答案

【判斷題】藥物效應動力學簡稱藥效學,是研究藥物對機體的作用?【單選題】以下關于Python語言中“縮進”說法正確的是:?????????????????????????????????????????????????????????????????????????…

數據結構及算法 -- 目錄

排序算法 -- 目錄 啦啦啦轉載于:https://www.cnblogs.com/ClassNotFoundException/p/7122848.html

Spring MVC集成測試

在Spring MVC中對控制器進行集成測試的一種方法是使用Spring提供的集成測試支持。 對于Junit4,此支持包括一個名為SpringJunit4ClassRunner的自定義Junit Runner和一個用于加載相關Spring配置的自定義批注。 樣本集成測試將遵循以下原則: RunWith(Spri…

spark 快速入門 java API

Spark的核心就是RDD,對SPARK的使用入門也就是對RDD的使用,包括action和transformation 對于Java的開發者,單單看文檔根本是沒有辦法理解每個API的作用的,所以每個SPARK的新手,最好按部就班直接學習scale, 那才是一個高…

網頁設計上機考試原題_Dreamweaver上機考試題目dreamweaver試題庫網頁制作試題.doc...

網頁設計上機考試題集注意:所有題目中涉及的素材都在考試文件夾內,其中圖片在下面的pic文件夾中,音樂、flash在media文件夾。1) 在1.html中的頂部添加一個錨點鏈接,點擊之能立即到達頁面最底端。2) 將1.html中的所有鏈接的默認樣式…

35數據結構與算法分析之---最短路徑

本系列是閱讀《數據結構與算法應用實踐教程》第2版 主編 李文書 北京大學出版社 的讀書筆記,加上自己的理解,更多的是學習的記錄與反思,如有不妥,歡迎指正,非常感謝。轉載于:https://www.cnblogs.com/guochaoxxl/p/712…

Quartz 2 Scheduler示例

Quartz是一個開源作業調度框架。 它可用于管理和計劃應用程序中的作業。 步驟1:建立已完成的專案 創建一個Maven項目,如下所示。 (可以使用Maven或IDE插件來創建它)。 步驟2:圖書館 Quartz依賴項已添加到Maven的po…

sql server 2008 com.microsoft.sqlserver.jdbc.SQLServerException: 通過端口 1433 連接到主機

原內容搬遷到了新網站,給你帶來的不便,敬請諒解! 》 http://www.suanliutudousi.com/2017/08/28/sql-server-2008-com-microsoft-sqlserver-jdbc-sqlserverexception-%E9%80%9A%E8%BF%87%E7%AB%AF%E5%8F%A3-1433-%E8%BF%9E%E6%8E%A5%E5%88%B0…

如何通過網線連接兩臺電腦快速傳輸數據?

介紹 我們經常需要拷貝文件會用到類似U盤等工具,但我們有時在傳輸大文件時又苦于沒有,那么大內存的轉存工具。這時候我們就可以通過一條小小的網線連接兩臺電腦,形成一個小的局域網傳輸數據,因為是通過網線傳輸,所以傳…

30分鐘內使用MongoDB

最近,我被NoSQL錯誤咬住了-或是我的同事Mark Atwell提出的“燃燒在哪里!” 運動。 盡管我無意于在不久的將來或可預見的將來回避友好的“ SELECT ... WHERE”,但我確實設法弄懂了一些代碼。 在本文中,我分享了我在NoSQL世界中首次…