天天看點

超越線程池:Java并發并沒有你想的那麼糟糕

很多人一直唠叨着并發中的新概念。然而,許多開發人員還沒有機會把過多的注意力都放在上面。在這篇文章中,我們将帶您了解java 8

streams、 hadoop、 apache spark、 quasar

fibers以及響應式程式設計,讓你迅速入門。尤其是如果你不經常用它們的話。一句話,它并不遙遠,它就在我們身邊。

超越線程池:Java并發并沒有你想的那麼糟糕

我們該怎麼做?

談到并發,一種很好的方式來形容目前的問題是來回答幾個小問題以便更好的了解它:

它是一個資料處理任務麼?如果是這樣的話,它可以分解為獨立的任務單元麼?

作業系統、虛拟機和你的代碼之間的關系是什麼?(本地線程 vs 輕量級線程)

有多少機器和處理器參與?(單核 vs 多核)

讓我們帶着問題,一起找出每個問題的最佳答案吧。

1、從線程池到并行流

在java

8中,我們了解到新的流api接口,它允許應用聚集操作,如篩選、排序或者映射資料流。流允許我們做的另一件事情是,在多核機器上應用并行操作。并行流

——通過把fork/join架構引入java 7将線程間的工作分離。java

6并發庫,我們看到了executorservice建立和處理我們的工作線程池,這不得不說是個進步。

fork/join也建立在executorservice之上,與傳統的線程主要的差別在于如何線上程和支援多核的機器間配置設定工作。用一個簡單的

executorservice你能完全控制工作線程之間的負載分布,确立每個任務的大小以便線程來處理。而fork/join,恰好有個work-stealing算法配置設定線程間的負載。簡而言之,這允許大型任務可以被分成更小單元,并在不同的線程間處理,最終我們可以知道——它是為了平衡線程間的

工作。然而,這并不是萬能的。

有時并行流會減慢你速度的,是以你需要多想想。在你的方法中使用parallelstream會導緻瓶頸和減速(在我們基準測試中跑慢了約15%左右)。假設我們已經運作多個線程,在其中一些我們使用parallelstream,線上程池中添加越來越多的線程。這可以很容易超過我們的核心處理能力,由于增加了上下文轉換一切都慢下來了。

小結:在單機上并行流使線程處理抽象化,在一定程度上這會均衡核心間的負載。然而,如果你想高效使用它們,記住硬體是關鍵而不是生産更多的線程而超出機器的處理能力。

2、apache hadoop和apache spark

接下來談多核機器、

pb級資料和任務,這跟所有從twitter提到的java或重載機器學習算法類似。談到hadoop,不得不說這個應用廣泛的架構及它的組

件:hadoop分布式檔案系統(hdfs)、資源管理平台(yarn)、資料處理子產品(mapreduce)和其他所需的類庫和工具(common)。

在這些元件上層還有一些其他很受歡迎的可選工具,比如運作在hdfs上的資料庫(hbase)、查詢語言平台(pig)和資料倉庫基礎結構(hive)。

apache spark

作為一種新資料處理子產品,以記憶體性能和快速執行的彈性分布式資料集(rdds)而出名,不同于不能高效使用記憶體和磁盤的hadoop

mapreduce。databricks公布的最新标準顯示當用少于10倍節點的時候,對1pb資料的排序spark比hadoop快三倍。

典型的hadoop用例在于查詢資料,而spark正以其快速的機器學習算法越來越出名。但這隻是冰山一角,databricks如是說:“spark 使應用程式在hadoop叢集中運作在記憶體中快100倍,當運作在磁盤中時甚至快10倍”。

小結:spark是在hadoop生态系統中的後起之秀,有一個常見的誤解是我們現在經常談它一些不合作或競争的事情,但是我認為我們在這正在看到這個架構的發展。

3、quasar fibers

我們有機會運作在hadoop,現在讓我們回到單機。事實上,在java多線程應用程式和集中在單線程上,讓我們眼光再長遠些。就我們而言,hotspot

jvm線程與本地系統線程相同,持有一個線程并且運作在”虛拟“線程中,這在fibers中都包含的。java沒有原生的fibers支援,但是不要擔

心,quasar通過parallel universe解決了我們的問題。

quasar

是一個開源的jvm庫。它支援fibers(也稱為輕量級線程),并且還充當架構的角色,在後面中我會提到。在這上下文轉換是它本質的名字。當我們核心數

量有限,一旦本地線程數量越大我們就會收到越來越多的上下文開銷。一種解決這個問題的方式是fibers,使用單線程支援”多線程“。這看起來像threadcepiton的一個執行個體。

fibers還可以被視為一個從線程池的進化,當我們通過應用并行流的時候避開了線程過載的危險。他們更容易衡量線程和允許令人可觀的并行”輕量“線程數量。它們不是為了取代線程,而是應該用在那些相對來說經常堵塞的代碼中,就如同擔任真正異步線程的角色。

小結:并行領域在java并發性中正提供一種新的思路,雖然還沒有版本釋出,但是值得一試。

4、actor和響應式程式設計

在響應式的官方言論中,最新的釋義有4原則:響應、有彈性、靈活性和消息驅動。這基本意味着快速、容錯、可伸縮的和支援非阻塞通信。

讓我們看看akka

actor是如果支援它的吧。簡單來講actor有一個狀态和一個特定的行為,通過交換消息溝通彼此的郵箱。一個actor系統作為一個整體應該被每個應

用程式建立,擁有一個層次結構将任務分解成更小的任務以便每個角色最多隻有一個監督的角色。一個角色也可以處理這個任務,通過委托給另一個角色将其進一步

分解或在執行個體失敗的情況下,将它回報給它的監督者。無論哪種方式,消息不應該包括行為或者共享可變的狀态,每個角色都有一個獨立的狀态和行為。

它是一個從大多數開發者在使用的并發模型的思考模式的轉移。盡管它起源于70年代,但是為了适應現代應用程式的要求,直到最近幾年它才複蘇。并行領域的quasar也支援actor,實作的主要差別在于fibers/輕量級線程。

小結:相反的,actor模型需要管理線程池,讓它遠離使用工具包。今天面對這種應用程式處理的問題,尤其在我們可以處理擁有更多核心的高并發系統方面又重新有了關注。

總結

關于使用并發或者并行算法,我們今天通過介紹4種方法來解決問題來應對你需要的場景。希望這有

助于激起你的興趣,以及在這大談并發話題的現在開拓下你的視野。超越線程池,有一種将這委托給語言及它的工具的趨勢——關注新的技術并應用它而不是花費無

數個小時解決競态條件和鎖。

來源:51cto