java 中ThreadLocal 的正確用法
java 中ThreadLocal 的正確用法
用法一:在關(guān)聯(lián)數(shù)據(jù)類中創(chuàng)建private static ThreadLocalThreaLocal的JDK文檔中說明:ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread。如果我們希望通過某個(gè)類將狀態(tài)(例如用戶ID、事務(wù)ID)與線程關(guān)聯(lián)起來,那么通常在這個(gè)類中定義private static類型的ThreadLocal 實(shí)例。
例如,在下面的類中,私有靜態(tài) ThreadLocal 實(shí)例(serialNum)為調(diào)用該類的靜態(tài) SerialNum.get() 方法的每個(gè)線程維護(hù)了一個(gè)“序列號(hào)”,該方法將返回當(dāng)前線程的序列號(hào)。(線程的序列號(hào)是在第一次調(diào)用 SerialNum.get() 時(shí)分配的,并在后續(xù)調(diào)用中不會(huì)更改。)
public class SerialNum {
// The next serial number to be assigned
private static int nextSerialNum = 0;
private static ThreadLocal serialNum = new ThreadLocal() {
protected synchronized Object initialValue() {
return new Integer(nextSerialNum++);
}
};
public static int get() {
return ((Integer) (serialNum.get())).intValue();
}
}
【例】
public class ThreadContext {
private String userId;
private Long transactionId;
private static ThreadLocal threadLocal = new ThreadLocal(){
@Override
protected 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;
}
}
用法二:在Util類中創(chuàng)建ThreadLocal
這是上面用法的擴(kuò)展,即把ThreadLocal的創(chuàng)建放到工具類中。
【例】例如hibernate的工具類:
public class HibernateUtil {
private static Log log = LogFactory.getLog(HibernateUtil.class);
private static final SessionFactory sessionFactory; //定義SessionFactory
static {
try {
// 通過默認(rèn)配置文件hibernate.cfg.xml創(chuàng)建SessionFactory
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
log.error("初始化SessionFactory失?。?, ex);
throw new ExceptionInInitializerError(ex);
}
}
//創(chuàng)建線程局部變量session,用來保存Hibernate的Session
public static final ThreadLocal session = new ThreadLocal();
/**
* 獲取當(dāng)前線程中的Session
* @return Session
* @throws HibernateException
*/
public static Session currentSession() throws HibernateException {
Session s = (Session) session.get();
// 如果Session還沒有打開,則新開一個(gè)Session
if (s == null) {
s = sessionFactory.openSession();
session.set(s); //將新開的Session保存到線程局部變量中
}
return s;
}
public static void closeSession() throws HibernateException {
//獲取線程局部變量,并強(qiáng)制轉(zhuǎn)換為Session類型
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}
}
用法三:在Runnable中創(chuàng)建ThreadLocal
還有一種用法是在線程類內(nèi)部創(chuàng)建ThreadLocal,基本步驟如下:
1、在多線程的類(如ThreadDemo類)中,創(chuàng)建一個(gè)ThreadLocal對象threadXxx,用來保存線程間需要隔離處理的對象xxx。
2、在ThreadDemo類中,創(chuàng)建一個(gè)獲取要隔離訪問的數(shù)據(jù)的方法getXxx(),在方法中判斷,若ThreadLocal對象為null時(shí)候,應(yīng)該new()一個(gè)隔離訪問類型的對象,并強(qiáng)制轉(zhuǎn)換為要應(yīng)用的類型。
3、在ThreadDemo類的run()方法中,通過調(diào)用getXxx()方法獲取要操作的數(shù)據(jù),這樣可以保證每個(gè)線程對應(yīng)一個(gè)數(shù)據(jù)對象,在任何時(shí)刻都操作的是這個(gè)對象。
public class ThreadLocalTest implements Runnable{
ThreadLocal<Studen> studenThreadLocal = new ThreadLocal<Studen>();
@Override
public void run() {
String currentThreadName = Thread.currentThread().getName();
System.out.println(currentThreadName + " is running...");
Random random = new Random();
int age = random.nextInt(100);
System.out.println(currentThreadName + " is set age: " + age);
Studen studen = getStudent(); //通過這個(gè)方法,為每個(gè)線程都獨(dú)立的new一個(gè)student對象,每個(gè)線程的的student對象都可以設(shè)置不同的值
studen.setAge(age);
System.out.println(currentThreadName + " is first get age: " + studen.getAge());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println( currentThreadName + " is second get age: " + studen.getAge());
}
private Studen getStudent() {
Studen studen = studenThreadLocal.get();
if (null == studen) {
studen = new Studen();
studenThreadLocal.set(studen);
}
return studen;
}
public static void main(String[] args) {
ThreadLocalTest t = new ThreadLocalTest();
Thread t1 = new Thread(t,"Thread A");
Thread t2 = new Thread(t,"Thread B");
t1.start();
t2.start();
}
}
class Studen{
int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
相關(guān)文章
java如何把逗號(hào)分隔的String字符串轉(zhuǎn)int集合
這篇文章主要介紹了java實(shí)現(xiàn)把逗號(hào)分隔的String字符串轉(zhuǎn)int集合,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
如何解決java.util.zip.ZipFile解壓后被java占用問題
這篇文章主要介紹了如何解決java.util.zip.ZipFile解壓后被java占用問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
java中json和對象之間相互轉(zhuǎn)換的運(yùn)用
本文主要介紹了java中json和對象之間相互轉(zhuǎn)換的運(yùn)用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-07-07
Java中Json字符串直接轉(zhuǎn)換為對象的方法(包括多層List集合)
下面小編就為大家?guī)硪黄狫ava中Json字符串直接轉(zhuǎn)換為對象的方法(包括多層List集合)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-08-08
Java concurrency之共享鎖和ReentrantReadWriteLock_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
本篇文章主要介紹了Java concurrency之共享鎖和ReentrantReadWriteLock,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-06-06
spring AOP的After增強(qiáng)實(shí)現(xiàn)方法實(shí)例分析
這篇文章主要介紹了spring AOP的After增強(qiáng)實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了spring面向切面AOP的After增強(qiáng)實(shí)現(xiàn)步驟與相關(guān)操作技巧,需要的朋友可以參考下2020-01-01

