ThreadLocal是用來處理多線程並發問題的一種解決方案。ThreadLocal是的作用是提供線程的局部變量,在多線程並發環境下,提供了與其他線程隔離的局部變量。通常這樣的設計的情況是因為這個局部變量是不適合放在全局變量進行同步處理的。比如在事務管理中,在service類中的涉及到事務的方法,每個事務的上下文都應該是獨立擁有數據庫的connection連接的,否則在數據提交回滾過程中就會產生沖突。
spring中使用ThreadLocal來設計TransactionSynchronizationManager類,實現了事務管理與數據訪問服務的解耦,同時也保證了多線程環境下connection的線程安全問題。
DataSourceTransactionManager的實現中,doBegin()方法開啟事務,我們看下它是怎么處理connection資源的。
首先從數據庫連接池中獲得一個connection,並構造一個connection包裝類,使用這個包裝類開啟事務,最后通過TransactionSynchronizationManager將connection與ThreadLocal綁定,事務提交或者回滾后,解除綁定。
TransactionSynchronizationManager中bindResource()的實現
Resource就是ThreadLocal,而這里的Map就是ThreadLocalMap的value,與當前線程關聯的ThreadLocal的值。
ThreadLocal又是如何為每個線程維護一個獨立的局部變量的呢?
首先在Thread類中,都會維護一個ThreadLocalMap映射表,這個映射表存儲的key是ThreadLocal本身,value則是我們存儲的局部變量object。
ThreadLocal類中get方法和set方法的實現。
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); } public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
我們再看getMap的實現
ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
從代碼實現中可以看出,每個線程Thread都會維護自己的ThreadLocalMap,這個map的key則是ThreadLocal類本身,而value則是我們保存的數據。ThreadLocal在多線程中是被公共持有的,被隔離的數據實際是存放在每個線程的ThreadLocalMap中的,只不過是通過ThreadLocal的引用得到每個線程維護的ThreadLocalMap中的value。