這篇文章主要介紹了Java中的ThreadLocal有什么用,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
除了使用synchronized同步符號外,Java中的ThreadLocal是另一種實現線程安全的方法。在進行性能測試用例的編寫過程中,比較簡單的辦法就是直接使用synchronized關鍵字,修飾對象、方法以及類。但是使用synchronized同步,這可能會影響應用程序的可伸縮性以及運行效率。但是如果要在多個線程之間共享對象又要保障線程安全,則除了synchronized之外沒有特別適合測試的方法。
Java中的ThreadLocal是實現線程安全的另一種方法,它不滿足同步要求,而是通過為每個線程提供Object的顯式副本來消除共享。由于不再共享對象,因此不需要同步,它可以提高應用程序的可伸縮性和運行效率。
很多人幾乎都沒有用過ThreadLocal類,因為在測試中能用到的地方實在太少了,而且測試腳本的性能一般來講都會很高,遠超被測服務的處理能力,所以即使全部使用synchronized也不會有任何問題。
但是ThreadLocal有很多真正的使用場景,這就是為什么將其添加到標準Java平臺庫中的原因。盡管知道現在多線程編程測試中對于ThreadLocal應用并不多,但是我會在后期多進行一些實踐,分享給各位。
以下是Java中ThreadLocal類的一些眾所周知的用法:
ThreadLocal非常適合實現每個線程單例類或每個線程上下文信息(例如事務ID)。
可以將任何非線程對象包裝在ThreadLocal中,并且將其使用變為線程安全的。ThreadLocal的經典示例之一是共享SimpleDateFormat。由于SimpleDateFormat不是線程安全的,因此使用全局格式化程序可能無法正常工作,但是使用每個線程格式化程序當然可以工作。
ThreadLocal提供了另一種擴展Thread的方法。如果要保留信息或將信息從一個方法調用傳遞到另一個方法,則可以使用ThreadLocal進行傳遞。
由于不需要修改任何方法,因此可以提供極大的靈活性。
沒有兩個線程可以看到彼此的ThreadLocal變量。J2EE應用程序服務器中有一個ThreadLocal的真實示例,該服務器使用Java ThreadLocal變量來跟蹤事務和安全上下文。
為了避免過多的創建和共享全局實例時的切換成本,將諸如數據庫連接之類的重對象作為ThreadLocal共享是很有意義的。
package com.fun.ztest.java;
import com.fun.frame.SourceCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* ThreadLocal演示測試類
*/
public class FunTester extends SourceCode {
public static Logger logger = LoggerFactory.getLogger(FunTester.class);
/**
* 這個是重點,通過ThreadLocal類重建線程私有的對象
*/
private static final ThreadLocal<Object> format = new ThreadLocal() {
@Override
protected Object initialValue() {
Object funTester = new Object();
logger.info("初始化對象,線程: {} 對象: {}", Thread.currentThread().getName(), funTester.hashCode());
return funTester;
}
};
public static void main(String args[]) throws IOException, InterruptedException {
for (int i = 0; i < 5; i++) {
Thread t = new Thread(new Fun());
t.start();
}
}
/**
* 獲取對象
*
* @return
*/
public static Object get() {
return format.get();
}
static class Fun implements Runnable {
@Override
public void run() {
logger.info("線程: {} 對象: {}", Thread.currentThread().getName(), FunTester.get().hashCode());
}
}
}INFO-> 當前用戶:fv,IP:10.60.193.37,工作目錄:/Users/fv/Documents/workspace/fun/,系統編碼格式:UTF-8,系統Mac OS X版本:10.16 INFO-> 初始化對象,線程: Thread-1 對象: 347384150 INFO-> 初始化對象,線程: Thread-2 對象: 142607688 INFO-> 線程: Thread-1 對象: 347384150 INFO-> 線程: Thread-2 對象: 142607688 INFO-> 初始化對象,線程: Thread-3 對象: 1008357237 INFO-> 初始化對象,線程: Thread-4 對象: 559951532 INFO-> 線程: Thread-3 對象: 1008357237 INFO-> 線程: Thread-4 對象: 559951532 INFO-> 初始化對象,線程: Thread-5 對象: 748958847 INFO-> 線程: Thread-5 對象: 748958847 Process finished with exit code 0
如果查看上述程序的輸出,則會發現,當不同的線程調用ThreadLocal類的get()方法而不是調用其initialValue()方法時,該方法將為該線程創建Object的互斥實例對象。 由于Object在線程之間不共享,并且實質上在創建它自己的線程安全對象或者方法的線程本地是完全線程安全的。
Java的ThreadLocal在JDK 1.2上引入,但后來在JDK 1.4中進行了泛化,以在ThreadLocal變量上引入類型安全性。
ThreadLocal通常與Thread一起使用,由Thread執行的所有代碼都可以訪問ThreadLocal變量,但是兩個線程看不到彼此的ThreadLocal變量。
每個線程都擁有ThreadLocal變量的互斥副本,該副本在線程完成或死亡(正常情況下或由于任何異常)后才有進行垃圾回收,因為這些ThreadLocal變量沒有任何其他線程引用。
Java中的ThreadLocal變量通常是類中的私有靜態字段,并在Thread中維護其狀態。
不要誤解ThreadLocal是Synchronization的替代方法,它全部取決于你自己的程序設計。如果設計允許每個線程擁有自己的對象副本,則可以使用ThreadLocal。
這里一個處理requestid的類,通過ThreadLocal使用,可以保證每個請求都擁有唯一的一個追蹤標記。
public class TraceKeyHolder {
private static ThreadLocal<String> threadLocal = new ThreadLocal();
public TraceKeyHolder() {
}
public static String getTraceKey() {
return (String)threadLocal.get();
}
public static void setTraceKey(String traceKey) {
threadLocal.set(traceKey);
}
public static void clear() {
threadLocal.remove();
}
}感謝你能夠認真閱讀完這篇文章,希望小編分享的“Java中的ThreadLocal有什么用”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。