資源描述:
《李國華總結spring如何處理線程并發(fā)》由會員上傳分享,免費在線閱讀,更多相關內容在應用文檔-天天文庫。
1、李國華總結:Spring如何處理線程并發(fā)我們知道Spring通過各種DAO模板類降低了開發(fā)者使用各種數據持久技術的難度。這些模板類都是線程安全的,也就是說,多個DAO可以復用同一個模板實例郵政表哥李國華而不會發(fā)生沖突。我們使用模板類訪問底層數據,根據持久化技術的不同,模板類需要綁定數據連接或會話的資源。但這些資源本身是非線程安全的,也就是說它們不能在同一時刻被多個線程共享。雖然模板類通過資源池獲取數據連接或會話,但資源池本身解決的是數據連接或會話的緩存問題,并非數據連接或會話的線程安全問題。按照傳統(tǒng)經驗,如果某個對象是非線程安全的,在多郵政表哥李國
2、華線程環(huán)境下,對對象的訪問必須采用synchronized進行線程同步。但Spring的DAO模板類并未采用線程同步機制,因為線程同步限制了并發(fā)訪問,會帶來很大的性能損失。此外,通過代碼同步解決性能安全問題挑戰(zhàn)性很大,可能會增強好幾倍的實現難度。那模板類究竟仰丈何種魔法神功,可以在無需同步的情況下就化解線程安全的難題呢?答案就是ThreadLocal!ThreadLocal在Spring中發(fā)揮著重要的作用,在管理request作用域的Bean、事務管理、任務調度、AOP等模塊都出現了它們的身影,起著舉足輕重的作用。要想了解Spring事務管理的底層
3、技術,ThreadLocal是必須攻克的山頭堡壘。ThreadLocal是什么早在JDK1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal為解決多線程程序的并發(fā)問題提供了一種新的思路。使用這個工具類可以很簡潔地編郵政表哥李國華寫出優(yōu)美的多線程程序。ThreadLocal很容易讓人望文生義,想當然地認為是一個“本地線程”。其實,ThreadLocal并不是一個Thread,而是Thread的局部變量,也許把它命名為ThreadLocalVariable更容易讓人理解一些。當使用ThreadLocal維護變量時,Th
4、readLocal為每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應的副本。從線程的角度看,目標變量就象是線程的本地變郵政表哥李國華量,這也是類名中“Local”所要表達的意思。線程局部變量并不是Java的新發(fā)明,很多語言(如IBMIBMXLFORTRAN)在語法層面就提供線程局部變量。在Java中沒有提供在語言級支持,而是變相地通過ThreadLocal的類提供支持。所以,在Java中編寫線程局部變量的代碼相對來說要笨拙一些,因此造成線程局部變量沒有在Java開發(fā)者中得到很好的普及。Thr
5、eadLocal的接口方法ThreadLocal類接口很簡單,只有4個方法,我們先來了解一下:voidset(Objectvalue)設置當前線程的線程局部變量的值。publicObjectget()該方法返回當前線程所對應的線程局部變量。publicvoidremove()將當前線程局部變量的值刪除,目的是為了減少內存的占用,該方法是JDK5.0新增的方法。需要指出的是,當線程結束后,對應該線程的局部變量將自動被垃圾回收,所以顯式調用該方法清除線程的局部變量并不是必須的操作,但它可以加快內存回收的速度。protectedObjectinitial
6、Value()返回該線程局部變量的初始值,該方法是一個protected的方法,顯然是為了讓子類覆蓋而設計的。這個方法是一個延遲調用方法,在線程第1次調用get()或set(Object)時才執(zhí)行,并且僅執(zhí)行1次。ThreadLocal中的缺省實現直接返回一個null。值得一提的是,在JDK5.0中,ThreadLocal已經支持泛型,該類的類名已經變?yōu)門hreadLocal。API方法也相應進行了調整,新版本的API方法分別是voidset(Tvalue)、Tget()以及TinitialValue()。ThreadLocal是如何做到為每一個線
7、程維護變量的副本的呢?其實實現的思路很簡單:在ThreadLocal類中有一個Map,用于存儲每一個線程的變量副本,Map中元素的鍵為線程對象,而值對應線程的變量副本。我們自己就可以提供一個簡單的實現版本:Java代碼//代碼清單1SimpleThreadLocalclassSimpleThreadLocal{privateMapvalueMap=Collections.synchronizedMap(newHashMap());publicvoidset(ObjectnewValue){valueMap.put(Thread.currentThr
8、ead(),newValue);//①鍵為線程對象,值為本線程的變量副本}publicObjectget(){Thread