原創:小姐姐味道(微信公衆號ID:xjjdog),歡迎分享,轉載請保留出處。java
碼農的世界歷來不缺少名詞。若是沒有,咱們就強行弄上幾個。這些名詞有垂直領域的知識縮寫,也有水平領域的抽象劃分。有的行雲流水無比順暢,有的晦澀難懂如便祕。程序員
在java的併發編程裏,就有一個比較晦澀的名詞,叫作線程封閉。在以往的技術交流中,常常有人提到這個東西。那它究竟是何方神聖,又有什麼用的功效呢?編程
你去搜索一下網絡上的文章,都會給你三個選項。安全
1)Ad-hoc線程封閉。bash
2)棧封閉。微信
3)ThreadLocal類。網絡
這些知識,戳破了那層窗戶紙,內容其實並不複雜。可怕的是這些名詞,爲了記住它們真是蛋碎了一地。多線程
咱們都知道,一個變量若是被多個線程所使用,勢必會引入同步問題。除了同步關鍵字,java引入了多種技術來達到多線程的同步問題,包括wait、notify,可重入Lock,AQS等。這種編程方式會增長程序的複雜性,使得代碼容易發生bug。架構
若是有一些數據,僅僅和線程有關,對線程外的數據是不可見的,那代碼寫起來就美好的多。實現了這種效果的技術,就統一稱爲線程封閉(thread confinement)。併發
這是前提。接下來咱們來看實現。
棧封閉屬於強行湊概念的一個範疇,它對寫代碼的人實際上是不可見的,它是JVM裏虛擬機棧或者本地方法棧的默認行爲。其實,咱們早就知道這個結果:成員變量是線程共享的,而局部變量是線程相關的。
很簡單的道理,但背後的原理須要深刻了解JVM。爲了瞭解這個功能,咱們須要對JVM的內存區域劃分有一個初步的瞭解。
JVM除了存儲空間最大的堆,還有線程相關的,正在運行的棧。棧封閉指的就是與線程相關的棧的相關行爲。
咱們也能夠再往下深挖一下。
虛擬機棧上的基本數據,實際上是一種稱做棧幀的東西。你能夠把棧幀理解成某個方法的執行。
在每一個方法壓棧後,其中存在局部變量表、操做數棧、動態鏈接、返回地址等信息。咱們的局部變量,其實就是存在與這些地方。因爲它們的祖先,最終只會指向一個線程,因此它們的做用範圍就被封閉了。
其實,java提供給開發者惟一的線程封閉API,就是ThreadLocal。
Thread類中,有一個成員變量threadLocals
,存放了與本線程相關的全部自定義信息。對這個變量的定義在Thread,而操做卻在ThreadLocal類中。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
...
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
複製代碼
關於ThreadLocal的用法有不少,好比經常使用的,每一個線程生成一個線程不安全的SimpleDateFormat
。
ThreadLocal<SimpleDateFormat> sdf = new ThreadLocal<SimpleDateFormat>();
sdf.set(new SimpleDateFormat());
複製代碼
關於ThreadLocal不作過多介紹,直接查看jdk源代碼便可獲取全部加成。
這些信息大多來源於《JAVA併發編程》一書。我特意搜索了一下Ad-hoc
這個名字的意思。
Ad-hoc模式就和之前的直連雙絞線概念同樣,是P2P的鏈接,因此沒法與其它網絡中的節點進行溝通,減小了干擾。 英文中做爲形容詞有「特別的」,「臨時」的含義。
實在是沒法理解爲何要用到這樣的命名。
這種方式,徹底靠實現者控制,因此很是脆弱。
咱們看一下這三種方式的歸宿。其中一種是JVM內部實現的,原理方面的知識;Ad-hoc是告訴用戶這種線程封閉式很困難的,趕忙放棄;到最後,咱們的手裏就只剩下了ThreadLocal了。
我彷彿看到了ThreadLocal在勝利的招手,同時個人名詞字典裏又多了幾個:線程封閉、棧封閉、Ad-hoc。
做者簡介:小姐姐味道 (xjjdog),一個不容許程序員走彎路的公衆號。聚焦基礎架構和Linux。十年架構,日百億流量,與你探討高併發世界,給你不同的味道。個人我的微信xjjdog0,歡迎添加好友,進一步交流。