ThreadLocal簡介
ThreadLocal是Java中的線程局部變量,用於存放線程的局部變量。java
ThreadLocal爲每一個線程的中併發訪問的數據提供一個副本,經過訪問副原本運行業務,這樣的結果是耗費了內存,可是確避免線程同步所帶來性能消耗,也減小了線程併發控制的複雜度。mysql
首先看一下ThreadLocal的API:sql
- get():返回此線程局部變量的當前線程副本中的值。
- protected T initialValue(): 返回此線程局部變量的當前線程的「初始值」。
- void remove(): 移除此線程局部變量當前線程的值。
- void set(T value): 將此線程局部變量的當前線程副本中的值設置爲指定值。
能夠看出ThreadLocal內部應該就是封裝了一個Map,本身實現ThreadLocal:數據庫
public class SimpleThreadLocal { private Map valueMap = Collections.synchronizedMap(new HashMap()); public void set(Object newValue) { //①鍵爲線程對象,值爲本線程的變量副本 valueMap.put(Thread.currentThread(), newValue); } public Object get() { Thread currentThread = Thread.currentThread(); //②返回本線程對應的變量 Object o = valueMap.get(currentThread); //③若是在Map中不存在,放到Map中保存起來 if (o == null && !valueMap.containsKey(currentThread)) { o = initialValue(); valueMap.put(currentThread, o); } return o; } public void remove() { valueMap.remove(Thread.currentThread()); } public Object initialValue() { return null; } }
以上代碼很好理解,JDK中的實現比這複雜,能夠自行查看源碼。安全
ThreadLocal基本使用
ThreadLocal對象一般用於防止對可變的單實例變量或全局變量進行共享。服務器
當一個類中使用了static成員變量的時候,必定要多問問本身,這個static成員變量須要考慮線程安全嗎?也就是說,多個線程須要獨享本身的static成員變量嗎?若是須要考慮,不妨使用ThreadLocal。多線程
例如,在單線程應用程序中可能會維護一個全局的數據庫鏈接,並在程序啓動的時候初始化這個鏈接,從而避免在調用每一個方法的時候都要傳遞一個Connection對象。因爲JDBC的鏈接對象不必定時線程安全的,所以,當多線程應用程序在沒有協同的狀況下使用全局變量時,就是否是線程安全的。經過把JDBC的鏈接保存到ThreadLocal對象中,每一個線程都會擁有本身的鏈接。併發
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class ConnectionManager { private static ThreadLocal<Connection> connectionHolder = new ThreadLocal<Connection>() { @Override protected Connection initialValue() { Connection conn = null; try { conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/test", "username", "password"); } catch (SQLException e) { e.printStackTrace(); } return conn; } }; public static Connection getConnection() { return connectionHolder.get(); } public static void setConnection(Connection conn) { connectionHolder.set(conn); } }
ThreadLocal須要注意的點
只要使用了「池」(線程池、鏈接池),在使用ThreadLocal時,尤爲須要注意,每一個線程在使用ThreadLocal的時候,必須對ThreadLocal執行一次clear操做,避免出現線程污染問題。ide
線程池中的線程是重複利用的,只要線程還在,ThreadLocal線程本地變量會一直存在系統中,在JavaEE的服務器中尤其明顯。性能