1. 程式人生 > >軟體事務記憶體導論(三)用Akka/Multiverse STM實現併發

軟體事務記憶體導論(三)用Akka/Multiverse STM實現併發

宣告:本文是《Java虛擬機器併發程式設計》的第六章,感謝華章出版社授權併發程式設計網站釋出此文,禁止以任何形式轉載此文。

用Akka/Multiverse STM實現併發

上面我們已經學習瞭如何在Clojure裡使用STM,我猜你現在一定很好奇如何在Java程式碼中使用STM。而對於這一需求,我們有如下選擇:

  • 直接在Java中使用Clojure STM。方法非常簡單,我們只需將事務的程式碼封裝在一個Callable介面的實現中就行了,詳情請參見第7章。
  • 喜歡用註解(annotation)的開發者可能會更傾向於使用Multiverse的STM API.
  • 除了STM之外,如果我們計劃使用角色(actor),那麼還可以考慮選擇Akka庫。

Multiverse是由Peter Veentjer主持開發的一個基於Java的STM實現。通過這個庫,我們可以在Java程式碼中使用註解來標識事務邊界。我們既可以用@TransactionalMethod註解將單個的方法標記為事務性的,也可以用@TransactionalObject註解將一個類的所有方法都標記為事務性的。為了與其他JVM上的語言進行整合,Multiverse還提供了一組豐富的API來控制事物的開始和結束。

Akka是一個由Jonas Boner主持開發的一個基於Scala的解決方案,該方案可以用於包括Java在內的很多其他運行於JVM上的語言。Akka不但提供了STM和基於角色(actor)的併發方案,還提供了將二者混合使用的選項。此外,Akka使用Multiverse作為其STM的實現並提供了ACI(ACID的子集)特性。

Akka的效能非常棒,並且由於它既支援STM又支援基於角色(actor)的模型(詳情請參見第8章),本章我們將會用它來實現演示Java STM的例子。


Akka/Multiverse中的事務

Akka的Java版採用了Multiverse的Clojure風格的STM。與Java那繁冗的程式碼風格相比,Clojure風格的Akka不會強迫我們在能夠修改可變實體之前就建立事務。如果我們沒有主動提供事務,則Akka/Multiverse就會自動把訪問請求封裝在一個事務中。所以當我們處於事務之中時,Akka的ref與Clojure的ref的表現是相同的;而當我們位於事務之外時,Akka ref的表現則更像是Clojure的atom。換句話說,想要使變更同步且有序就必須使其在事務中完成,否則變更將是同步但無序的。在任何情況下,Akka都會保證對於ref的更改是原子的、隔離的且一致的,並同時提供了不同等級的協調粒度。

在Akka中,我們既可以用寫程式碼的方式在事務層對事務進行配置,也可以通過配置檔案在應用程式/JVM層進行配置。例如,我們可以將一個事務定義為只讀(readonly),於是Akka將不再允許任何位於該事務範圍內的Akka引用被修改。這樣做的好處是,如果我們將一些不可變的事務設定為只讀,則程式效能將會得到一定的提升。除此之外,我們還可以控制在衝突情況下事務的最大重試次數。當然,還有很多其他引數可供我們配置,詳情請參閱Akka的幫助文件。

Akka擴充套件了Multiverse中的巢狀事務(請參見6.9節),所以我們能夠很方便地在事務中呼叫啟動其他事務的函式。預設情況下,這些內部事務或巢狀事務都是與其外部事務融為一體的。

使用Akka引用和事務

Clojure中的ref是在語言層定義的,而 Akka是一個公共類庫所以不能依賴任何現有語言的支援。所以Akka在其akka.stm包中提供了一個託管事務引用(managed transactional reference)Ref和一些為原始型別而設的特殊類,如IntRef、LongRef等。Ref(以及所有原始型別的特化引用)代表指向型別T的一個不可變值的託管可變實體(managed mutable identity)。像Integer、Long、Double、String這些型別以及其他不可變型別都符合作為值物件的(value object)條件。如果我們用了自己定義的類,則必須保證這個類是不可變的。也就是說,這個自定義的類只能包含final欄位。

我們可以建立一個Ref的例項作為託管事務引用,其值可以在初始化時指定或乾脆不指定(預設為null)。如果想獲得引用的當前值,可以使用get()函式。如果要使引用指向另一個可變實體,則可以使用swap()函式。這些呼叫可以在我們提供的事務裡執行,但如果我們沒提供事務的話,它們也可以在其各自的事務中執行。

當多個執行緒都試圖更改同一個託管引用時,Akka可以保證只有一個變更可以寫入記憶體而其他變更將全部重做。Akka有專門的事務工具負責管理事務跨越記憶體柵欄的過程。也就是說,Akka(通過Multiverse)保證了在事務中一個託管ref變更的提交會先於後續所有其他事務對該ref的讀操作,即該變更對所有其他事務可見。


丁 一

英文名ticmy,本站的翻譯主編,主要負責譯文的翻譯和校對工作,目前就職於阿里巴巴,對併發程式設計、JVM執行原理、正則等頗有興趣;個人部落格:http://www.ticmy.com/;同時,還是戶外攝影愛好者。