ThreadLocal的意义和实现
可以想像,如果一個對象的可變的變量被多個線程訪問時,必然是不安全的。
在單線程應用可能會維持一個全局的數據庫連接,并在程序啟動時初始化這個連接對象,從而避免在調用每個方法時都傳遞一個Connection對象。ThreadUnsafe類就是這樣做的:
public class ThreadUnsafe {private static Connection connection = DriverManager.getConnection(DB_URL);public void Connection getConnection{ /* 在多線程應用中,connection 在被多個線程訪問 */return connection;} }但是JDBC連接對象不一定是線程安全的,在多個線程訪問到Connection時,就可能出現安全問題。為了解決這個問題,ThreadLocal類提供了安全的做法。
通過將JDBC的Connection對象封裝在ThreadLocal對象中,當每個線程訪問需要Connection對象時,ThreadLocal對象返回的是一個副本。
public class ThreadUnsafe {private static ThreadLocal<Connection> connectionHodler = new ThreadLocal<>{public Connection initialValue() {return DriverManager.getConnection(DB_URL);}} public void Connection getConnection{ /* 即使多個線程可以訪問,依然安全 */return connectionHolder.get();} }ThreadLocal是如何實現這種功能?
首先,在Thread類中有一個threadLocals的實例變量,這是一個Map,保存了與線程相關的ThreadLocal對象封裝的變量。
/* ThreadLocal values pertaining to this thread. This map is maintained* by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null;當線程初次調用ThreadLocal對象的get方法時,就會調用initialValue()來獲取初始值。
/*** 返回ThreadLocal封裝的對象。*/public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) { /* 首次調用map為null */ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue(); /* 首次調用的返回值 */}/*** 初始化封裝在ThreadLocal中對象的值。*/private T setInitialValue() {T value = initialValue();Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value); //為什么鍵值是ThreadLocal對象?,因為一個線程對象可能有使用多個ThreadLocal封閉的變量elsecreateMap(t, value);return value;}/*** 更新封裝在ThreadLocal中對象的值*/public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);} public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this);}ThreadLocalMap getMap(Thread t) {return t.threadLocals;}/*** 創建一個Map,用于保存ThreadLocal和其封裝的對象。*/void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue);}注意:ThreadLocalMap在ThreadLocal類中聲明,卻是在Thread類中使用的,原因在于,當線程結束時,這些特定于線程的值保存在Thread對象中,當線程終止后,這些值會作為垃圾回收。
ThreadLocal類實現的是一種線程封閉技術。將變量封閉在單線程中,從而避免同步。
參考:?《Java?Concurrency?in?Practice》?P35&P37?
?
轉載于:https://www.cnblogs.com/yvkm/p/10664109.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的ThreadLocal的意义和实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《Java编程的逻辑》第三部分 泛型与容
- 下一篇: cmd下的一些小技巧