這是why技術的第29篇原創文章html
以前在寫《這道Java基礎題真的有坑!我求求你,認真思考後再回答。》這篇文章時,我在8.1小節提到了快速失敗和失敗安全機制。java
可是我發現當我搜索"快速失敗"或"失敗安全"的時候,檢索出來的結果百分之90以上都是在說Java集合中是怎麼實現快速失敗或失敗安全的。程序員
在我看來,說到快速失敗、失敗安全時,咱們首先想到的應該是這是一種機制、一種思想、一種模式,它屬於系統設計範疇,其次才應該想到它的各類應用場景和具體實現。而不是立馬想到了集合,這樣就有點本末倒置的感受了。web
能夠看一下wiki上對於快速失敗和失敗安全的描述:apache
快速失敗:http://en.wikipedia.org/wiki/Fail-fast編程
失敗安全:http://en.wikipedia.org/wiki/Fail-safe安全
簡而言之:系統運行中,若是有錯誤發生,那麼系統當即結束,這種設計就是快速失敗。系統運行中,若是有錯誤發生,系統不會中止運行,它忽略錯誤(可是會有地方記錄下來),繼續運行,這種設計就是失敗安全。多線程
本文就對比一下Java集合中的快速失敗、失敗安全和Dubbo框架中的快速失敗、失敗安全。併發
讀完以後,你就知道Java集合中實現和Dubbo中的實現就大不同。框架
沒有誰比誰好,只有結合場景而言,誰比誰更合適而已。
現象:在用迭代器遍歷一個集合對象時,若是遍歷過程當中對集合對象的內容進行了增長、刪除、修改操做,則會拋出ConcurrentModificationException。
原理:迭代器在遍歷時直接訪問集合中的內容,而且在遍歷過程當中使用一個 modCount 變量。集合在被遍歷期間若是內容發生變化,就會改變modCount的值。每當迭代器使用hashNext()/next()遍歷下一個元素以前,都會檢測modCount變量是否爲expectedmodCount值,是的話就返回遍歷;不然拋出ConcurrentModificationException異常,終止遍歷。
注意:這裏異常的拋出條件是檢測到 modCount!=expectedmodCount 這個條件。若是集合發生變化時修改modCount值恰好又設置爲了expectedmodCount值,則異常不會拋出。所以,不能依賴於這個異常是否拋出而進行併發操做的編程,這個異常只建議用於檢測併發修改的bug。
場景:java.util包下的集合類都是快速失敗的,不能在多線程下發生併發修改(迭代過程當中被修改)。
上面的知識點我在《這道Java基礎題真的有坑!我求求你,認真思考後再回答。》這篇文章中第三小節已經抽絲剝繭般的詳細說明了,有興趣的能夠閱讀一下:
現象:採用失敗安全機制的集合容器,在遍歷時不是直接在集合內容上訪問的,而是先複製原有集合內容,在拷貝的集合上進行遍歷。
原理:因爲迭代時是對原集合的拷貝進行遍歷,因此在遍歷過程當中對原集合所做的修改並不能被迭代器檢測到,因此不會觸發ConcurrentModificationException。
缺點:基於拷貝內容的優勢是避免了ConcurrentModificationException,但一樣地,迭代器並不能訪問到修改後的內容,即:迭代器遍歷的是開始遍歷那一刻拿到的集合拷貝,在遍歷期間原集合發生的修改迭代器是不知道的。這也就是他的缺點,同時,因爲是須要拷貝的,因此比較吃內存。
場景:java.util.concurrent包下的容器都是安全失敗,能夠在多線程下併發使用,併發修改。
好比以前文章說到的CopyOnWriteArrayList:
集合部分涉及到的參考連接:https://www.cnblogs.com/ygj0930/p/6543350.html
在描述快速失敗和失敗安全在Dubbo中的體現以前,咱們必須先說說Dubbo中的集羣容錯機制,由於快速失敗和失敗安全是其容錯機制中的一種。
仍是看以前出現的圖片:
其中,集羣 Cluster 用途是將多個服務提供者合併爲一個 Cluster Invoker,並將這個 Invoker 暴露給服務消費者。這樣一來,服務消費者只需經過這個 Invoker 進行遠程調用便可,至於具體調用哪一個服務提供者,以及調用失敗後如何處理等問題,如今都交給集羣模塊去處理。
集羣模塊是服務提供者和服務消費者的中間層,爲服務消費者屏蔽了服務提供者的狀況,這樣服務消費者就能夠專心處理遠程調用相關事宜。
對於容錯方式官網上是這樣的說的:
注意哦,官網說的是主要提供了這樣幾種,並無徹底列舉,經過查看源碼你能夠看到:
org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker
有九個實現類,說明官方提供了九種容錯方式供你選擇:
而本文主要討論的是:
org.apache.dubbo.rpc.cluster.support.FailfastClusterInvoker org.apache.dubbo.rpc.cluster.support.FailsafeClusterInvoker
爲了方便演示快速失敗和失敗安全在Dubbo中的體現,咱們須要先搭建一個簡單的Demo項目,搭建過程我就不演示了,這一小節僅對Demo的關鍵地方進行說明:
服務端接口以下:
服務端接口實現以下:
休眠3秒,模擬業務超時。
服務端Dubbo xml配置以下:
消費端Dubbo xml配置以下:
消費端在Test類中消費以下:
快速失敗對應的實現類是:
org.apache.dubbo.rpc.cluster.support.FailfastClusterInvoker
啓用該實現類,只須要在Dubbo xml中指定cluster屬性爲failfast:
先看一下實現類上的註釋是怎麼寫的:
Execute exactly once, which means this policy will throw an exception immediately in case of an invocation error. Usually used for non-idempotent write operations。
FailfastClusterInvoker 只會進行一次調用,失敗後當即拋出異常。適用於冪等操做,好比新增記錄。
實現類的源碼以下:
執行結果以下:
失敗安全對應的實現類是:
org.apache.dubbo.rpc.cluster.support.FailsafeClusterInvoker
啓用該實現類,只須要在Dubbo xml中指定cluster屬性爲failsafe:
先看一下實現類上的註釋是怎麼寫的:
When invoke fails, log the error message and ignore this error by returning an empty Result. Usually used to write audit logs and other operations
FailsafeClusterInvoker 是一種失敗安全的 Cluster Invoker。所謂的失敗安全是指,當調用過程當中出現異常時,FailsafeClusterInvoker 僅會打印異常,而不會拋出異常。適用於寫入審計日誌等操做。
實現類的源碼以下:
執行效果以下,首先能夠看到超時異常被捕獲:
因此雖然超時了,可是在Test類中,仍是打印出了returnStr:
本週輸出這篇文章實屬不易。
因爲週六公司年會與運動會,我有幸當選了某隊隊長,因此本週週一到週五工做以外的時間都在忙碌着運動會的物質籌備、數據統計等相關工做。僅僅有早起的一小會空擋時間能隨手翻翻書,可是寫文章時間是不夠的。
週六活動開始,從早上6點30分起牀,到晚上23點作完最後的收尾工做,忙碌了整整一天。所幸的是我所在的小隊在10支隊伍中脫穎而出,勇奪第一。
在戰況異常激烈的拔河環節,在全部拉拉隊員整齊劃一,嘶聲吶喊的口號聲中,參賽隊員體現出的那種堅韌不拔、咬牙死撐的精神,深深的打動了我。一共有兩次輪空的機會,咱們隊伍都與之擦肩而過,可是咱們一次又一次的擊敗了實力強勁的對手,仍是握住了總決賽拔河的繩子。因爲對手輪空一輪,因此體力充沛,咱們遺憾告負。可是在裁判沒有吹哨以前,咱們永不言棄。
全部項目比完以後,我所在隊伍最終的總積分排名第一。在最終結果沒有宣佈以前,咱們永不言棄。
週日,和我從小一塊兒長大的表姐結婚,早上7點多去現場幫忙。中午吃飯時我都沒敢喝太多酒,由於我想着這周的文章還沒寫,我得保持清醒。可是看到姐姐和姐夫站在大熒幕下的那一刻,我仍是感動的熱淚盈眶。下午陪家人玩了一下午。晚上到家以後已經很是疲倦了,可是我仍是輸出了這篇文章。
女友問我這周能不能不寫,我想了一下說:不能。由於那一瞬間我想到了,路遙先生在《早晨從中午開始》中的一句話:只有初戀般的熱情和宗教般的意志,人才有可能成就某種事業。
這也和年會中的一頁PPT很是的符合:把你的所有,奉獻給你熱愛的一切。
我是一個普通的程序員,可是我熱愛這個行業。
若是把Java集合的實現和Dubbo框架的實現分開來看,感受這是兩個不一樣的知識點,可是再往上抽離,能夠發現它們都是快速失敗機制與失敗安全機制的實現方式。仍是有着千絲萬縷的聯繫。
仍是以前說的,快速失敗機制與失敗安全機制,沒有誰比誰好,只有結合場景而言,誰比誰更合適而已。
與本文相關的文章還有下面兩篇,歡迎閱讀:
《這道Java基礎題真的有坑!我求求你,認真思考後再回答。》
才疏學淺,不免會有紕漏,若是你發現了錯誤的地方,還請你留言給我指出來,我對其加以修改。
若是你以爲文章還不錯,你的轉發、分享、讚揚、點贊、留言就是對我最大的鼓勵。
感謝您的閱讀,我堅持原創,十分歡迎並感謝您的關注。
以上。
歡迎關注公衆號【why 技術】,堅持輸出原創。願你我共同進步。