这是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 技术】,坚持输出原创。愿你我共同进步。