什么是ThreadLocal
ThreadLocal并不能從字面上理解為線程的本地實現(xiàn)版本,因為它并不是一個線程,而是ThreadLocal Variable(線程局部變量)。它的功能非常簡單,就是為每一個使用該變量的線程都提供一個變量值的副本,使得每一個線程都可以獨立地改變自己的副本,而不會和其他線程珠副本沖突。從線程的角度看,就好像每一個線程都完全擁有該變量。
首先看看ThreadLocal的方法:
1、get()
返回當(dāng)前線程的線程局部變量的副本,當(dāng)?shù)谝淮握{(diào)用這個方法時會自動創(chuàng)建并且初始化一個線程局部變量的副本。
2、initialValue()
返回該線程的線程局部變量的當(dāng)前線程的初始值,這個方法只在第一次調(diào)用get()方法的時候被調(diào)用一次。如果在調(diào)用get()方法之前已經(jīng)調(diào)用了set()方法,那么這個方法將不會被調(diào)用。
這個方法是一個protected的方法,不能直接調(diào)用該方法,只有在其子類中將該方法重寫才能改變它的行為。在默認(rèn)情況下,該方法的返回值為null。
3、set()
設(shè)置當(dāng)前線程的線程局部變量副本的值。大多數(shù)的應(yīng)用程序都不需要調(diào)用這個方法,可以通過initialValue()方法來設(shè)置當(dāng)前線程局部變量的值。
4、remove()
移除當(dāng)前線程局部變量的值。這樣做的目的是可以降低當(dāng)前線程的存儲空間的使用量,這是Java1.5的新增方法。
ThreadLocal的使用
ThreadLocal的使用方法有兩種,一種方法是自己實現(xiàn)ThreadLocal的子類,并重寫initialValue()方法。另一種方法是定義一個表態(tài)的ThreadLocal實例,通過使用set()方法來初始化這個線程局部變量的值。
如果希望線程局部變量初始化的時候就具有值,那么需要自己實現(xiàn)ThreadLocal的子類并重寫該方法,通常使用一個內(nèi)部匿名類對ThreadLocal進(jìn)行子類化。例如在下面的例子中,SerialNum類為每一個類分配一個序號:

public class SerialNum
{
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();
}
}
{
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();
}
}
同樣,也可以不采用實現(xiàn)ThreadLocal子類的方法來實現(xiàn)同樣的功能,如下所示:

public class SerialNum1
{
private static int nextSerialNum=0;
private static ThreadLocal serialNum=new ThreadLocal();
public static int get()
{
if(serialNum.get()==null)
serialNum.set(new Integer(nextSerialNum++));
return ((Integer)(serialNum.get())).intValue();
}
}
{
private static int nextSerialNum=0;
private static ThreadLocal serialNum=new ThreadLocal();
public static int get()
{
if(serialNum.get()==null)
serialNum.set(new Integer(nextSerialNum++));
return ((Integer)(serialNum.get())).intValue();
}
}
SerialNum類的使用非常簡單,因為get()方法是static的,所以在需要獲取當(dāng)前線程的序號時,簡單地調(diào)用int serial=SerialNum.get();即可。
在線程是活動并且ThreadLocal對象是可訪問時,該線程就持有一個到該線程局部變量副本的隱含引用。當(dāng)該線程運行結(jié)束后,該線程擁有的所有線程局部變量的副本都將失效,并等待垃圾收集器收集。
ThreadLocal 幾點作用:
1)可以啟到類似單態(tài)類的作用,實際上是要使某變量達(dá)到線程安全時,可以使用這種方式;
2)可以結(jié)合HttpServletRequest,HttpServletResponse,ServletContext等來實現(xiàn)使用運行時數(shù)據(jù);
在使用ThreadLocal 時一般是使用get()方法,但在使用這個方法時,會先調(diào)用set()方法,具體的用途可以在創(chuàng)建ThreadLocal 變量時指定,也可以
重寫set()方法,如果不想設(shè)定set()方法,可以在創(chuàng)建ThreadLocal 變量時指定,如下:

protected synchronized Object initialValue() {
return new User();
}

或者使用:public static void setCurrentUser(User user) { currentUser.set(user); }手工給ThreadLocal 變量賦值(user),
要獲得User對象時,可以使用 User u = (User)currentUser.get();即直接調(diào)用get()方法,來返回set()方法所設(shè)置的值(也可以不寫
此方法,而直接在定義變量時,重寫initialValue()方法,此方法返回所要設(shè)置的值或?qū)ο?,這里是User對象,然后調(diào)用User類的其他方法.