今天要講的話題就是網上Java一直熱議的多線程并發問題的解決!這個問題在不知道的時候是很高大上,但是了解了之後也就那麼一回事,原理要懂!
我們知道傳統web容器進行http請求處理的時候,是需要用到httpServletRequest、httpServletResponse,而servelet對象是一個無狀态的單列對象(singleton),對于同一個servlet對象的多個請求,servlet的service方法将在一個多線程的環境中并發執行,是以web容器預設采用單執行個體(單servlet執行個體)多線程的方式來處理Http請求,這時候就會造成多線程之間的資料不安全,每個線程都可以修改同一個變量的資料!針對這個問題的解決方案,一般很多程式員會采用兩種方案,第一:“規避問題”,但它是非文法檢查級别的禁止(此問題不能根本上杜絕程式員犯這樣的錯誤);第二:在整個請求周期中引入ThreadLocal模式,使整個過程的對象通路都線程安全化。是以要引用優秀的程式設計思想threadLocal.
多線程并發問題的具體解決方案細節:java.lang.ThreadLocal類。ThreadLocal類在維護變量時,實際使用了目前線程(Thread)中的一個叫做ThreadLocalMap的獨立副本。每個線程可以獨立修改屬于自己的副本而不會互相影響。關于ThreadLocalMap介紹,如下:
1、ThreadLocalMap變量屬于線程的内部屬性,不同的線程擁有完全不同的ThreadLocalMap變量;
2、線程中的ThreadLocalMap變量的值是在ThreadLocal對象進行set或者get操作時創;
3、在建立ThreadLocalMap之前,會首先檢查目前線程中的ThreadLocalMap變量是否存在,如果不存在則建立一個;如果存在,則使用目前線程已建立的ThreadLocalMap
4、使用目前線程的ThreadLocalMap的關鍵在于使用目前的ThreadLocal的實列作為key進行存儲。
可能講到這裡,很多人就會問,那怎麼使得多線程資料之間是安全的,這就是我接下來要說的——ThreadLocal資料通路隔離,它做到了兩個方面:
第一:縱向隔離——線程與線程之間的資料通路隔離。因為每個線程在進行對象通路時,通路的都是各個線程自己的ThreadLocalMap;
第二:橫向隔離:同一個線程中,不同的ThreadLocal實列操作的對象之間互相隔離ThreadLocalMap采用ThreadLocal實列作為key來保證。
在同一個線程不同開發層次中共享資料,往往使用ThreadLocal模式(設計模式),可以對執行邏輯與執行資料進行有效解耦。接下來介紹實作他的兩個主要步驟:
第一:建立一個類,并在其中封裝一個靜态的threadLocal變量,使其成為一個共享資料環境;
第二:在類中實作通路靜态ThreadLocal變量的靜态方法(設定和取值)。
然而,又有人會問,使用上面那些是因為線程不安全的情況下實施的,那麼線上程安全的時候就不要,那我怎麼去區分是否是線程安全呢!這個問題很好解決,因為不存線上程安全問題的方面總結起來也就那麼幾點:
1、方法簽名中的任何參數變量;
2、處于方法内部的局部變量;
之是以上面那些是線程安全的,因為都處于方法體的内部!