執行緒併發總結

騎蝸牛看世界發表於2016-05-07

Synchronized關鍵字主要解決多執行緒共享資料同步問題。
ThreadLocal使用場合主要解決多執行緒中資料因併發產生不一致問題。
ThreadLocal和Synchonized都用於解決多執行緒併發訪問。但是ThreadLocal與synchronized有本質的區別:
synchronized是利用鎖的機制,使變數或程式碼塊在某一時該只能被一個執行緒訪問。而ThreadLocal為每一個執行緒都提供了變數的副本,使得每個執行緒在某一時間訪問到的並不是同一個物件,這樣就隔離了多個執行緒對資料的資料共享。而Synchronized卻正好相反,它用於在多個執行緒間通訊時能夠獲得資料共享。
Synchronized用於執行緒間的資料共享,而ThreadLocal則用於執行緒間的資料隔離。當然ThreadLocal並不能替代synchronized,它們處理不同的問題域。Synchronized用於實現同步機制,比ThreadLocal更加複雜。
1、Java中synchronized用法
使用了synchronized關鍵字可以輕鬆地解決多執行緒共享資料同步問題。
synchronized關鍵字可以作為函式的修飾符,也可作為函式內的語句,也就是平時說的同步方法和同步語句塊。如果再細的分類,synchronized可作用於instance變數、object reference(物件引用)、static函式和class literals(類名稱字面常量)身上。
synchronized取得的鎖都是物件;每個物件只有一個鎖(lock)與之相關聯;實現同步是要很大的系統開銷作為代價的,甚至可能造成死鎖,所以儘量避免無謂的同步控制。
synchronized的4種用法 :
1.方法宣告時使用,執行緒獲得的是成員鎖.
2.對某一程式碼塊使用,synchronized後跟括號,括號裡是變數,執行緒獲得的是成員鎖.
3.synchronized後面括號裡是一物件,此時,執行緒獲得的是物件鎖.
4.synchronized後面括號裡是類,此時,執行緒獲得的是物件鎖.
2、java.lang.ThreadLocal()的用法
一、概述
ThreadLocal是什麼呢?其實ThreadLocal並非是一個執行緒的本地實現版本,它並不是一個Thread,而是threadlocalvariable(執行緒區域性變數)。也許把它命名為ThreadLocalVar更加合適。執行緒區域性變數(ThreadLocal)其實的功用非常簡單,就是為每一個使用該變數的執行緒都提供一個變數值的副本,是Java中一種較為特殊的執行緒繫結機制,是每一個執行緒都可以獨立地改變自己的副本,而不會和其它執行緒的副本衝突。
ThreadLocal是如何做到為每一個執行緒維護變數的副本的呢?其實實現的思路很簡單,在ThreadLocal類中有一個Map,用於儲存每一個執行緒的變數的副本。
概括起來說,對於多執行緒資源共享的問題,同步機制採用了“以時間換空間”的方式,而ThreadLocal採用了“以空間換時間”的方式。前者僅提供一份變數,讓不同的執行緒排隊訪問,而後者為每一個執行緒都提供了一份變數,因此可以同時訪問而互不影響。
二、API說明
ThreadLocal()
建立一個執行緒本地變數。
T get()
返回此執行緒區域性變數的當前執行緒副本中的值,如果這是執行緒第一次呼叫該方法,則建立並初始化此副本。
protected T initialValue()
返回此執行緒區域性變數的當前執行緒的初始值。最多在每次訪問執行緒來獲得每個執行緒區域性變數時呼叫此方法一次,即執行緒第一次使用 get() 方法訪問變數的時候。如果執行緒先於 get 方法呼叫 set(T) 方法,則不會線上程中再呼叫 initialValue 方法。
若該實現只返回 null;如果程式設計師希望將執行緒區域性變數初始化為 null 以外的某個值,則必須為 ThreadLocal 建立子類,並重寫此方法。通常,將使用匿名內部類。initialValue 的典型實現將呼叫一個適當的構造方法,並返回新構造的物件。
void remove()
移除此執行緒區域性變數的值。這可能有助於減少執行緒區域性變數的儲存需求。如果再次訪問此執行緒區域性變數,那麼在預設情況下它將擁有其 initialValue。
void set(T value)
將此執行緒區域性變數的當前執行緒副本中的值設定為指定值。許多應用程式不需要這項功能,它們只依賴於 initialValue() 方法來設定執行緒區域性變數的值。
在程式中一般都重寫initialValue方法,以給定一個特定的初始值。
三、典型例項
四、總結
ThreadLocal使用場合主要解決多執行緒中資料因併發產生不一致問題。
ThreadLocal為每個執行緒的中併發訪問的資料提供一個副本,通過訪問副本來執行業務,這樣的結果是耗費了記憶體,單大大減少了執行緒同步所帶來效能消耗,也減少了執行緒併發控制的複雜度。
ThreadLocal不能使用原子型別,只能使用Object型別。ThreadLocal的使用比synchronized要簡單得多。
五、ThreadLocal使用的一般步驟
1、在多執行緒的類(如ThreadDemo類)中,建立一個ThreadLocal物件threadXxx,用來儲存執行緒間需要隔離處理的物件xxx。
2、在ThreadDemo類中,建立一個獲取要隔離訪問的資料的方法getXxx(),在方法中判斷,若ThreadLocal物件為null時候,應該new()一個隔離訪問型別的物件,並強制轉換為要應用的型別。
3、在ThreadDemo類的run()方法中,通過getXxx()方法獲取要操作的資料,這樣可以保證每個執行緒對應一個資料物件,在任何時刻都操作的是這個物件。
我們知道Spring通過各種DAO模板類降低了開發者使用各種資料持久技術的難度。這些模板類都是執行緒安全的,也就是說,多個DAO可以複用同一個模板例項而不會發生衝突。
我們使用模板類訪問底層資料,根據持久化技術的不同,模板類需要繫結資料連線或會話的資源。但這些資源本身是非執行緒安全的,也就是說它們不能在同一時刻被多個執行緒共享。
雖然模板類通過資源池獲取資料連線或會話,但資源池本身解決的是資料連線或會話的快取問題,並非資料連線或會話的執行緒安全問題。
按照傳統經驗,如果某個物件是非執行緒安全的,在多執行緒環境下,對物件的訪問必須採用synchronized進行執行緒同步。但Spring的DAO模板類並未採用執行緒同步機制,因為執行緒同步限制了併發訪問,會帶來很大的效能損失。
此外,通過程式碼同步解決效能安全問題挑戰性很大,可能會增強好幾倍的實現難度。那模板類究竟仰丈何種魔法神功,可以在無需同步的情況下就化解執行緒安全的難題呢?答案就是ThreadLocal!
ThreadLocal在Spring中發揮著重要的作用,在管理request作用域的Bean、事務管理、任務排程、AOP等模組都出現了它們的身影,起著舉足輕重的作用。要想了解Spring事務管理的底層技術,ThreadLocal是必須攻克的山頭堡壘

相關文章