1. 程式人生 > >討喜的隔離可變性(十三)角色的特性

討喜的隔離可變性(十三)角色的特性

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

基於角色的併發模型降低了隔離可變性程式設計的難度,但該模型在適用場景上還是存在一些限制。

由於角色是通過訊息來進行彼此間通訊的,所以在那些沒有強制不可變性的語言中,我們就必須人工來保證訊息都是不可變的。傳遞可變訊息將導致執行緒安全問題並最終使整個應用陷入共享可變性的險境當中,所以當手頭的輔助工具還沒有發展到可以幫助我們自動查驗訊息的不可變性之前,保證訊息不可變性的重擔暫時還是得由我們程式設計師來肩負。

角色都是各自非同步執行的,彼此之前可以通過傳遞訊息來進行協作。但某些角色的意外失敗有可能導致其他角色餓死——一個或多個角色可能會一直等待某些關鍵的協作訊息,而這些訊息可能由於本應發出該訊息的角色失敗而永遠無法抵達。因此,我們需要在編碼時更加謹慎,在角色中加入異常情況的處理邏輯,並將錯誤訊息傳播給那些等待響應的角色。

當兩個或多個角色互相等待對方發來的訊息時,則所有角色都將陷入死鎖。我們必須在設計層面謹小慎微,以確保角色在協作過程中不會陷入死鎖狀態。與此同時,我們應該使用超時來保證程式不會由於協作環節中個別角色失敗無法響應而導致其他角色無限期的等待。

角色一次只能處理一個訊息請求,所以無論是動作訊息還是請求某個響應或狀態的訊息,在角色內部都是順序處理的。對於那些只讀任務而言,這種做法可能會降低程式整體的併發度。所以我們最好還是用粗粒度的訊息來設計應用程式。此外,我們還可以通過設計單向的“傳送並遺忘”型別的訊息代替雙向訊息來減少角色之間的相互等待。

並非所有的應用程式都適合用基於角色的模型實現。只有在待解決的任務可以被拆分成多個彼此相互獨立的子任務並且子任務之間只有少量互動的情況下,使用角色才是合適的。但如果子任務之間需要頻繁互動或者子任務們需要通過形成一個裁決集(quorum)的形式來進行協作,則使用基於角色的模型就是不合適的。而對於這類問題,我們可以嘗試將基於角色的模型與其他併發模型混搭或乾脆考慮重新設計。

小結

角色是單執行緒的,彼此間通過傳遞訊息來進行互動。通過本章的學習,我們瞭解到角色有如下特性:

  • 降低了隔離可變性的使用門檻
  • 從根本上消除了同步問題
  • 提供了高效的單向訊息,但同時也提供了不怎麼高效的傳送並等待功能
  • 可擴充套件性非常強;同時由於角色都是單執行緒的,所以我們可以很方便地用執行緒池來對其進行管理
  • 允許我們傳送訊息,但同時也通過介面的方式支援型別化版本(在Akka中)。
  • 允許我們通過事務來完成多角色之間的協作

雖然角色為我們提供了一種強大的程式設計模型,但該模型在某些方面仍有一些限制。例如,如果我們在使用角色進行設計的時候沒有考慮周到,則程式可能存在角色餓死或死鎖的潛在風險。此外,我們還需要保證訊息的不可變性,這一點在沒有語言層面的支援的環境中尤為重要。

下一章我們將學習如何在各種JVM支援的語言中使用角色。


方 騰飛

花名清英,併發網(ifeve.com)創始人,暢銷書《Java併發程式設計的藝術》作者,螞蟻金服技術專家。目前工作於支付寶微貸事業部,關注網際網路金融,併發程式設計和敏捷實踐。微信公眾號aliqinying。