關於ThreadLocal,java中有一個很相似的對比機制:clone.
他們的思想都是,給當前的線程/方法一個本地變量的copy,各個線程/方法雖然看起來是共享了一個變量,但相互之間並不干擾交互。
ThreadLocal是非常輕量級的保證線程安全的機制,不涉及鎖,不涉及同步阻塞。完全是線程內部的一個變量。
那有的同學可能會問,既然這樣幹嘛還要設計成類的成員變量,直接在方法裏面聲明然後在方法之間傳遞不就好了。這樣其實完全可以,但是相對來說代碼結構會更加複雜,不利於後期的維護,我們來看一個ThreadLocal的例子:
- public class ConnectionManager {
- /** 線程內共享Connection,ThreadLocal通常是全局的,支持泛型 */
- private static ThreadLocal<Connection> threadLocal = new ThreadLocal<Connection>();
- public static Connection getCurrConnection() {
- // 獲取當前線程內共享的Connection
- Connection conn = threadLocal.get();
- try {
- // 判斷連接是否可用
- if(conn == null || conn.isClosed()) {
- // code : 創建新的Connection賦值給conn
- // code : 保存Connection
- threadLocal.set(conn);
- }
- } catch (SQLException e) {
- }
- return conn;
- }
- /**
- * 關閉當前數據庫連接
- */
- public static void close() {
- // 獲取當前線程內共享的Connection
- Connection conn = threadLocal.get();
- try {
- // 判斷是否已經關閉
- if(conn != null && !conn.isClosed()) {
- // 關閉資源
- conn.close();
- // 移除Connection
- threadLocal.remove();
- conn = null;
- }
- } catch (SQLException e) {
- // 異常處理
- }
- }
- }
這是ThreadLocal應用的一個典型場景,大家可以琢磨一下兩個問題:
1.如果不用ThreadLocal會怎麼樣?
2.如果不用ThreadLocal該怎麼做?
如果最後你覺得在這種場景下ThreadLocal是最好的選擇那麼你基本就理解了ThreadLocal和它的使用場景。
接下來看一下Threadlocal的內部實現原理。
如果看過Thread和ThreadLocal源碼的同學會發現,在Thread類內部有一個ThreadLocal.ThreadLocalMap這樣的一個成員變量。在調用ThreadLocal的set/get時,程序會根據當前線程來獲取對應的ThreadLocalMap,即Thread對象的ThreadLocal.ThreadLocalMap這個表,然後把值放入該Map中,即這個值是在線程內部而非ThreadLocal內部。這樣在一個Thread對象裏可以存放多個TheadLocal對象。