JVM線程池發展趨勢
多線程已經成為大多數開發者的興趣所在了。他們努力嘗試想找出最優策略來解決這個問題。過去已經有各種嘗試去標準化這些方案。特別是隨著大數據,實 時分析等問題領域的興起,又存在著新的挑戰。在這個方向需要走的一步是“Doug Lea”的作品(一部巨作),以并發框架(JSR 166)的形式提供給我們。
現在開始區分并發和并行性。這些只是不同的策略,而且市面上有很多框架提供,都能幫我們達到相同的目的。但在選擇的時候如果能同時知道他們內部的實 現細節對我們也是大有好處的。本文將要探究JVM中線程池和線程共享的一些穩定有效的選項。當然,隨著多核處理器的廣泛使用,新的問題也隨之而來。開發人 員也開始思考利用高級硬件的“mechanical sympathy”(譯者注:表示底層硬件的運作方式以及與硬件運行方式協同的軟件編程)來提高性能。
個人以為,當討論線程池時,目前廣泛應用的主要有下述機制:
- Executor框架提供的線程。
- LMAX的Ring Buffer概念 (譯者注:Ring Buffer即環形緩沖,LMAX是一種新型零售金融交易平臺,其框架能以低延遲產生大量交易,LMAX建立在JVM平臺上。
- 基于Actor(事件)的實現。 </ol>
- 減少線程創建導致的延遲
- 通過優化線程數量,可以解決資源不足的問題。 </ol>
- 可封裝
- 可監督
- 可配置執行
- 位置透明
- 重試機制 </ul>
并發框架下的線程池選項:
首先,我個人不贊同使用當下流行的線程池概念,而應該使用工作隊列的概念。簡而言之,在一個執行框架可供選擇的各種不同選項都是基于某種順序數據結 構,如數組或隊列(阻塞或非阻塞)之類的,比如ConcurrentLinkedQueue(并發鏈式隊列),ArrayBlockingQueue(數 組阻塞隊列), LinkedBlockingQueue(鏈式阻塞隊列)等等。文檔表明,盡管它們的使用環境各不相同,但他們隱含的本質/數據結構有相同的性質,如順序 插入和遍歷。
優勢:
這些可以使應用程序和服務器應用響應更快。使用線程池看似一個很不錯的解決方案但是卻有一個根本性的缺陷:連續爭用問題。這里是Java中關于一些并發框架下線程池選項的討論。
Disruptor(環形緩沖):
(LMAX的一個基于環形緩沖區的高性能進程間消息庫)LMAX的開發人員使用一個干擾框架來解決連續爭用問題,這個框架是基于一個叫環形緩沖的數 據結構。它可能是線程間發送消息的最有效方式了。它是隊列的一種替代實現方式,但它又和SEDA和Actors(譯者注:這兩種都是和Disruptor 類似的并發模型)有一些共同特征。向Disruptor中放入消息需要兩步,第一步申請一個環形緩沖的槽位,槽位可為用戶提供寫對應數據的記錄。然后需要 提交該條記錄,為了能靈活使用內存,2步法是必須的。只有經過提交,這條消息才能對消費者線程可見。下圖描述了環狀緩沖這個數據結構(Disruptor 的核心):
(譯者注:LMAX的核心是一個業務邏輯處理器,而該業務邏輯處理器的核心是Disruptor,這是一個并發組件,能夠在無鎖的情況下實現網絡的Queue并發操作)
Disruptor在多核平臺上能達到很低的延遲同時又有高吞吐量,盡管線程程間需要共享數據以及傳遞消息。
它的獨特之處在于鎖和免爭用結構。它甚至不使用CAS或內存保護。若想了解關于它的更多細節,這里有一篇不錯的文章和官網。使用Disruptor的一個缺點(事實上也算不上缺點)是,你需要提前告知Disruptor應用程序完成任務所需要的線程數。
基于事件:
對于傳統線程池機制,一個強大的替代方案就是基于事件模型。這種基于事件的線程輪詢/線程池/線程調度機制在函數式編程中很常見。關于這個概念的一個非常流行的實現是基于actor的系統(譯者注:Scala的并發系統),Akka已成為其實際上的標準。(譯者注:Akka,一種善于處理進程間通信的框架)
Actors是非常輕量級的并發實體。它們使用一種事件驅動的接收循環來異步處理消息。消息模式匹配可以很方便地表述一個actor的行為。它們提 高了抽象級別從而使寫,測試,理解和維護并發/分布式系統更加容易。讓你專注于工作流——消息如何流入系統——而不是低層次的基本概念如線程,鎖以及套接 字IO。一個線程可以分配多個或單個actor,而且兩種模型都是依需要選擇的。
像Akka這種基于actor的系統的優勢有如下所列:
注:調試一個基于actor的系統是一個非常艱難的事情。
Disruptor使用一個線程一個消費者模式,不同于Actors使用N個線程M個消費者模式。比如,你可以擁有任意多的actors,然后它們 會被分散到一些數目固定的線程中(通常是一個核一個線程),至于其他的部分,actor模型就和Disruptor模型差不多了;特別是用于批處理的時 候。
我最初在因特網上搜多到的答案也說明開源空間中關于確定JVM選項基準的貢獻還是有一些的。其中一個選項是ExecutorBenchmarkt。它是一個并行任務的開源測試框架。它是用Scala編寫的,但是可以用于Java和Scala負載。
簡而言之,快速發展的軟硬件行業在呈現新挑戰給我們的同時也提供了大量解決應用程序容錯性和響應性的方法。對于不可預知的少量線程,我建議使用 JDK并發框架中的線程池機制。對于大量規模相似的任務,個人建議使用Disruptor。Disruptor的確是有一點學習曲線,但在性能和擴展性方 面的收獲遠遠值得投入的學習時間。在應用程序需要某種重試或管理機制,以及分布式任務時,建議使用Akka的Actor模型。盡管結果還有可能被其它因素 所影響,你還是會選擇map reduce或fork/join模型或是其它自定義實現一個分布式應用程序。
原文鏈接: dzone 翻譯: ImportNew.com - 范 忠瑞譯文鏈接: http://www.importnew.com/15082.html