美文网首页Effective Java
第64条:努力使失败保持原子性

第64条:努力使失败保持原子性

作者: 小小辉_710a | 来源:发表于2017-09-12 18:04 被阅读0次

当对象抛出异常之后,通常我们期望这个对象仍然保持在一种定义良好的可用状态之中,即使失败是发生在执行某个操作的过程中间。对于受检的异常而言,这尤为重要,因为调用者期望能从这种异常中进行恢复。一般而言,失败的方法调用应该使对象保持在被调用之前的状态。具有这种属性的方法被称为具有失败原子性

有几种途径可以实现这种效果。最简单的办法莫过于设计一个不可变的对象(见第15条:使可变性最小化)。如果对象是不可变的,失败原子性就是显然的。如果一个操作失败了,它可能会阻止创建新的对象,但是永远也不会使已有的对象保持在不一致的状态之中,因为当每个对象被创建之后它就处于一致的状态之中,以后也不会再发生变化。

对于在可变对象上执行操作的方法,获得失败原子性最常见的办法是,在执行操作之前检査参数的有效性(见第38条:检查参数的有效性)。这可以使得在对象的状态被修改之前,先抛出适当的异常。例如,考虑第6条中的Stadc.pop方法:

如果取消对初始大小(size)的检査,当这个方法企图从一个空栈中弹出元素时,它仍然会抛出异常。然而,这将会导致size域保持在不一致的状态(负数)之中,从而导致将来对该对象的任何方法调用都会失败。此外,那时候pop方法抛出的异常也不适于抽象(见第61条:抛出与抽象相对应的异常)。

一种类似的获得失败原子性的办法是,调整计算处理过程的顺序,使得任何可能会失败的计算部分都在对象状态被修改之前发生。如果对参数的检査只有在执行了部分计算之后才能进行,这种办法实际上就是上一种办法的自然扩展。例如,考虑TreeMap的情形,它的元素被按照某种特定的顺序做了排序。为了向TreeMap中添加元素,该元素的类型就必须是可以利用TreeMap的排序准则与其他元素进行比较的。如果企图增加类型不正确的元素,在tree以任何方式被修改之前,自然会导致ClassCastException异常。

第三种获得失败原子性的办法远远没有那么常用,做法是编写一段恢复代码(recovery code),由它来拦截操作过程中发生的失败,以及使对象回滚到操作开始之前的状态上。这种办法主要用于永久性的(基于磁盘的(disk-based))数据结构。

最后一种获得失败原子性的办法是,在对象的一份临时拷贝上执行操作,当操作完成之后再用临时拷贝中的结果代替对象的内容。如果数据保存在临时的数据结构中,计算过程会更加迅速,使用这种办法就是件很自然的事。例如,Collections.sort在执行排序之前,首先把它的输入列表转到一个数组中,以便降低在排序的内循环中访问元素所需要的开销。这是出于性能考虑的做法,但是,它增加了一项优势:即使排序失败,它也能保证输入列表保持原样。

虽然一般情况下都希望实现失败原子性,但并非总是可以做到。例如,如果两个线程企图在没有适当的同步机制的情况下,并发地修改同一个对象,这个对象就有可能被留在不一致的状态之中。因此,在捕获了ConcurrentModificationException异常之后再假设对象仍然是可用的,这就是不正确的。错误(相对于异常)通常是不可恢复的,当方法抛出错误时,它们不需要努力保持失败原子性。

即使在可以实现失败原子性的场合,它也并不总是人们所期望的。对于某些操作,它会显著地增加开销或者复杂性。但一旦意识到这个问题,实现失败原子性往往轻松自如。

一般而言,作为方法规范的一部分,产生的任何异常都应该让对象保持在该方法调用之前的状态。如果违反这条规则,API文档就应该清楚地指明对象将会处于什么样的状态。遗憾的是,大量现有的API文档都未能做到这一点。

相关文章

  • 第64条:努力使失败保持原子性

    当对象抛出异常之后,通常我们期望这个对象仍然保持在一种定义良好的可用状态之中,即使失败是发生在执行某个操作的过程中...

  • 第 76 条:努力使失败保持原子性

  • 第七十六条:努力使失败保持原子性

    当对象抛出异常之后,通常我们期望这个对象仍然保持在一种定义良好的可用状态之中,即使失败是发生在执行某个操作的过程中...

  • mysql中的事务隔离性

    事务拥有原子性、隔离性、一致性、持久性(acid)。 原子性:要么全成功,要么全失败。 隔离性:事务之间必须保持隔...

  • 事务

    原子性(Atomicity) 事务的整个过程如原子操作一样,最终要么全部成功,或者全部失败,这个原子性是从最终结果...

  • 原子性

    原子性: 要么全部执行成功要么全部执行失败

  • MySQL之事务隔离级别

    1. 事务特性 原子性 事务的原子性是指,事务包含一些列的原子性操作,且其执行结果只能是:全部成功或者全部失败,不...

  • 原子性、可见性、有序性

    原子性:原子性是指一个操作是不可分割的,要么全部执行,要么全部失败。jvm 定义了以下 8 种操作是具有原子性的(...

  • 知识点总结3-数据库

    1.ACID ⑴ 原子性(Atomicity) 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚,不可拆...

  • 数据库事务ACID四大特性

    原子性(Atomicity) 原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。 例:A给B转账100元...

网友评论

    本文标题:第64条:努力使失败保持原子性

    本文链接:https://www.haomeiwen.com/subject/diaxsxtx.html