ITEM 76: 尽力时故障原子性

ITEM 76: STRIVE FOR FAILURE ATOMICITY
  即使在一个对象在执行操作的过程中发生了故障,抛出异常之后,通常也希望该对象仍然处于定义良好的可用状态。对于受控异常尤其如此,调用者需要从中恢复。一般来说,失败的方法调用应该使对象保持在调用之前的状态。具有此属性的方法称为故障原子性方法( failure-atomic)。
  有几种方法可以实现这种效果。最简单的是:设计不可变对象(item 17)。如果一个对象是不可变的,实现故障原子性方法是毫无成本的。如果一个操作失败,它可能会阻止创建新对象,但它不会让现有对象处于不一致的状态,因为每个对象的状态在创建时是一致的,此后无法修改。
  对于操作可变对象的方法,实现故障原子性的最常见方法是在执行操作之前检查参数的有效性(item 49)。这将导致在对象修改开始之前抛出大多数异常。例如 item 7 的 Stack.pop 方法:

public Object pop() {
  if (size == 0)
    throw new EmptyStackException();
  Object result = elements[--size];
  elements[size] = null; // Eliminate obsolete reference return result;
}

  如果取消了初始大小检查,该方法在尝试从空堆栈中取出元素时仍然会抛出异常。同事,它会使size 字段处于不一致的(负的)状态,从而导致以后对该对象的任何方法调用失败。此外,pop 方法抛出的 ArrayIndexOutOfBoundsException 也不适合抽象(item 73)。
  与实现故障原子性密切相关的一种方法是对计算进行排序,以便可能失败的部分在修改对象的部分之前发生。当不执行部分计算就不能检查参数时,这种方法是前一种方法的自然扩展。例如,考虑 TreeMap 的情况,它的元素是按照某种顺序排序的。为了向TreeMap添加元素,元素的类型必须能够使用 TreeMap 的排序进行比较。在以任何方式修改树之前,尝试添加类型不正确的元素自然会失败,并会出现 ClassCastException,这是在树中搜索元素的结果。
  实现故障原子性的第三种方法是对对象的临时副本执行操作,并在操作完成后用临时副本替换对象的内容。一旦数据存储在临时数据结构中,就可以更快地执行计算,这种方法自然就会出现。例如,一些排序函数在排序之前将其输入列表复制到数组中,以减少在排序的内部循环中访问元素的开销。这样做是为了提高性能,但是作为额外的好处,它确保了在排序失败时不会改变输入列表。
  实现故障原子性的最后一种方法是编写恢复代码,拦截在操作过程中发生的故障,并导致对象将其状态回滚到操作开始前的状态。这种方法主要用于持久的(基于磁盘的)数据结构。
  虽然故障原子性通常是可取的,但它并不总是可以实现的。例如,如果两个线程试图在没有适当同步的情况下并发地修改同一个对象,该对象可能会处于不一致的状态。因此,假设一个对象在捕获了 ConcurrentModificationException 之后仍然可用是错误的。错误是不可恢复的,因此在抛出 AssertionError 时,您甚至不需要试图保持故障原子性。
  即使在可能存在故障原子性的地方,也不总是可取的。对于某些操作而言,它将显著增加成本或复杂性。也就是说,一旦您意识到问题的存在,通常可以轻松地实现故障原子性。
  总之,作为规则,作为方法规范一部分的任何生成的异常都应该使对象保持在方法调用之前的相同状态。在违反此规则的地方,API文档应该清楚地指出对象将处于什么状态。不幸的是,现有的大量API文档都不能满足这一理想。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,718评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,683评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,207评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,755评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,862评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,050评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,136评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,882评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,330评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,651评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,789评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,477评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,135评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,864评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,099评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,598评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,697评论 2 351