Java線程與併發編程實踐----額外的併發工具類

  一、併發集合

  java.util包下提供了很多的集合類,如ArrayList、TreeSet、HashMap,但是這些

  集合都是非線程安全的,並且對於單列集合的迭代器,採用的是快速失敗機制,當正在迭代

  遍歷的集合被其它線程修改時,便會拋出 java.util.ConcurrentModificationException。

  這顯然對於多線程操作的集合是十分不方便的,但早Colections這個工具類中有方法可以返回

  線程安全的集合,然而這種集合對於高併發環境,性能十分低下。

  於是,java.util.concurrent包下提供了很多相關集合的類,即併發集合,這些集合

  具有併發性能和高擴展性,並且返回的是弱一致性的迭代器,即不再是快速失敗機制的迭代器。

  大致描述如上,具體翻查jdk。下面單獨研究使用併發集合完成生產者消費者的問題。

  使用BlockingQueue和ArrayBlockingQueue實現生產者消費者:

  ArrayBlockingQueue是一個由數組支的有界阻塞隊列,當隊列滿載時,put()方法會阻塞,當

  隊列爲空時,take()方法阻塞,因此用這種隊列可以很輕鬆的實現消費者、生產者。

  轉到https://blog.51cto.com/12222886/1963884

  深入學習ConcurrentHashMap:

  重點了解此方法。

  ConcurrentHashMap是一個線程安全的集合,但是在多線程德操作之下它並不是線程安全

  的,例如如下代碼:

  試想,當我們再判斷完之後,還未put之前,有一條線程向map中put進一個鍵爲something的值,

  然後我們再繼續put,那麼剛纔的那個值是不是就被覆蓋了?這就產生了安全問題。。爲了保證

  安全我們應該這樣做:

  以上可以解決安全問題,但是性能會被降低。。我們應該使用ConcurrentHashMap所提供的

  一個API,putIfabsent(K key,V value),它的含義是,假如鍵值不存在,便put進去,它是線程

  安全的,並且性能更高,相當於如下代碼:

  二、原子變量

  和對象監聽器關聯的那些內置鎖一直以來都有性能不佳的問題,後來出現了

  很多非阻塞算法,可大大提高性能和擴展性。

  java.util.concurrent.atomic提供了高效非阻塞算法。它支持單個變量可進行無

  鎖及線程安全的操作。有如下原子類:

  原子變量用於實現計數器、序列生成器以及其它構造。在線程高爭用的環境下,這些構造要求互斥

  而不影響性能。假如有如下代碼:

  上述代碼中volatile保證了可見性,synchronized保證了互斥性,在多線程環境下,上述代碼沒有

  問題,然而在高爭用的環境中性能會很低。我們可以用原子變量代替上述代碼:

  上述代碼完全保證了可見性,互斥性以及操作的原子性,並且由於它實現了高爭用下的非阻塞算法,

  因此它的性能相對來說高了很多。

  那麼問題來了,爲什麼原子變量能夠提高性能????

  Compare-and-swap(CAS機制)

  Compare-and-swap(CAS機制)是一個針對非搶佔式微處理器的一條指定指令的寬泛術語,這條

  指令讀取內存的位置,比較讀到的值和期望的值,當讀到值和期望值匹配時,就將新值存儲到該內存

  位置,否則,什麼也不發生。

  CAS支持原子的讀-改-寫序列,通常這樣使用:

  (1)從地址A讀取x

  (2)在x進行多步計算

  (3)使用CAS將A值從x變爲y。在進行這些操作時,如果A值沒有改變,CAS就成功了

  那CAS到底優越之處在哪呢?

  上面的代碼使用synchronized,高爭用環境下的監聽鎖會導致過多的上下文切換,這樣會阻礙所有線程

  並且導致應用程序無法很好的擴展。而CAS機制不適用監聽器來是操作原子化,而是在修改ID的值之前會

  進行判斷,如果該值沒發生過變化,就將新值賦值給該變量,如果發生變化了就什麼也不做,而在這中間

  對值是否發生過變化的判斷是利用CAS指令完成的。

  java.util.concurrent.locks.ReentrantLock就使用了CAS機制改善了性能,原子類也利用了CAS機制。



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