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