ThreadLocal<T> 類行是 .NET Framework 4.0 才開始支持的類型,MSDN 的解釋只有簡單的一句話:提供數據的線程本地存儲,其提供的實例代碼也不太好,有點為了演示而演示的目的。所以,一眼望去,我們並不知道這個類型有什麼用。
一:ThreadLocal 在 JAVA 中的應用
其實這個類型在 JAVA 中早就存在了,並且在 JAVA 的體系中的應用也被廣泛提到,現在我們把這些概念用 .NET 來描述一遍。
先看段 JAVA 代碼,這端代碼存在於 Hibernate 中:
private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() throws InfrastructureException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
s = getSessionFactory().openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new InfrastructureException(ex);
}
return s;
}
要看懂或者明白這段代碼的意義,我們需要了解一般 WEB應用服務器 關於對於 Request 和 Thread 的處理:
一次請求會產生一個 Thread 嗎?不會,WEB引擎(如ASP.NET 引擎)會維護一個托管線程池,多次請求間可能會用到一個線程(PS:嚴格意義上來說,是異步,不是線程,但包裝成托管線程的模樣)。
接著繼續說代碼:首先判斷當前線程中有沒有放進去 session ,如果還沒有,那麼通過 sessionFactory().openSession() 來創建一個 session ,再將 session set 到線程中,實際是放到當前線程的 ThreadLocal 對象上。要注意的是,其他線程中是取不到這個 session 的。
二:ThreadLocal 在 .NET 中的表現
首先,兩個類型在 API 聲明上是不一致的,但是目的都是一樣的:
讓各個線程維持自己的變量。
現在,寫一段代碼測試下:
public partial class Handler : System.Web.UI.Page
{
private static ThreadLocal<Sample> sampLocal = new ThreadLocal<Sample>();
protected void Page_Load(object sender, EventArgs e)
{
if (!sampLocal.IsValueCreated)
{
sampLocal.Value = new Sample();
}
Response.Write("Thread.CurrentContext.ContextID=" + Thread.CurrentContext.ContextID + "<br/>");
Response.Write("Thread.CurrentThread.ManagedThreadId=" + Thread.CurrentThread.ManagedThreadId + "<br/>");
Response.Write("sampLocal=" + sampLocal.Value.GetHashCode() + "<br/>");
}
}public class Sample
{
}
其最有可能的輸出是:
Thread.CurrentContext.ContextID=0
Thread.CurrentThread.ManagedThreadId=9
sampLocal=57902434
不停滴刷新,如果 threadid 為 9 ,則得到的 sampLocal 是同一個對象。
三:ThreadLocal 與 static
可以理解為
1:ThreadLocal 是線程內的 static 變量,也許其名字命名為 ThreadStatic 更好?
2:static 是全部線程都可共用的變量。
四:ThreadLocal 的用處
那麼,這段代碼為什麼要這麼設計,也許基於一點:
避免參數傳遞的訪問方式,但是要注意get()到的是那同一個共享對象,並發訪問問題要靠其他手段來解決;
參考:ThreadLocal