前置觀念 - 必須了解Thread, Thread.currentThread()被呼叫的機制, call stack機制.
ThreadLocal的目的 : 把變數存在currentThread中, 讓每個執行中的Thread都有自己的一份Copy, 而且彼此之間不會互相影響.
實作概念 :
public class ThreadLocalConcept{
private Map<Thread,Object> localMap = Collections.synchronizedMap(new HashMap<Thread,Object>());
public void set(Object obj){
this.localMap.put(Thread.currentThread(), obj);
}
public Object get(){
this.localMap.get(Thread.currentThread());
}
}
基本上就是這個localMap會放著各個Thread對應的變數, 因此在不同的Thread中呼叫到的Value都會是獨立的.
用途範例 : 在DAO中拿到Login User
一般來說Login User都是放在Session中, 但是平常我們使用的Service & DAO都會是Singleton, 是共用的, 因此不能夠將Login User放入
我們可以利用一個Request-Response是一個獨立Thread的特性, 搭配ThreadLocal將Login User存入各個Thread中,就可以拿到相對應的Login User了
Step1. 建立一個共用的Thread Local
public class LoginUserUtil{
public static ThreadLocal<User> local = new ThreadLocal<User>();
public static User getUser(){
return local.get();
}
public static void setUser(User user){
local.set(user);
}
}
step2. 在BaseAction/BaseServlet/BaseController內放入LoginUser
public class BaseAction extends ...{
public doBaseRequest(){
User user = this.getRequest().getSession().getAttribute("loginUser");
LoginUserUtil.set(user);
}
}
step3. 在DAO中拿出LoginUser - 完工!!
public class XXXDAOImpl extends ...{
public void updateData(Data data){
data.setUpdateUser(LoginUserUtil.get());
this.update(data);
}
}

那在Dao updte的時候 , 為何不直接呼叫session拿取User物件就好?還要透過ThredLocal的作法 ?
這個範例只是個ThreadLocal的應用。 只要在同一個Thread內,讓你在程式一開始拿到的物件,只要透過一個static method的setter放入,就可以在程式的任何layer透過static getter拿到這個物件,就像變魔術一樣,你從左耳塞入一枚硬幣,卻從右邊口袋拿出同一枚硬幣。 回答你的問題,每個Framework也許不太相同,但是在一般Servlet(Action) - Service - DAO的架構下,能在DAO拿到Session的情形除非 1. 你將Session當作參數傳入Service,再將Session當作參數傳入DAO 2. Framework有static method支援 相較之下,其實ThreadLocal只需要一點點程式碼,就可以做到利用static method傳資料的快速方法。