Java多線程併發訪問解決方案

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()方法獲取要操作的數據,這樣可以保證每個線程對應一個數據對象,在任何時刻都操作的是這個對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章