`
lvhuiqing
  • 浏览: 253252 次
  • 性别: Icon_minigender_1
  • 来自: 沈阳
社区版块
存档分类
最新评论

3.4. Immutability(不变性)

阅读更多
3.4. Immutability(不变性)
The other end-run around the need to synchronize is to use immutable objects [EJ Item 13]. Nearly all the atomicity and visibility hazards we've described so far, such as seeing stale values, losing updates, or observing an object to be in an inconsistent state, have to do with the vagaries of multiple threads trying to access the same mutable state at the same time. If an object's state cannot be modified, these risks and complexities simply go away.
为了避免使用同步机制的另外一种方式是使用不可变对象。迄今为止我们描述过的所有原子性和可见性隐患(例如过期数据、update丢失、或者看到一个对象的非稳定状态),都是由于多个线程在同一时间访问相同的可变状态造成的。但是如果对象的状态是不可修改的,那么这些危险和复杂性就全部消除了。
An immutable object is one whose state cannot be changed after construction. Immutable objects are inherently thread-safe; their invariants are established by the constructor, and if their state cannot be changed, these invariants always hold.
immutable对象是指该对象的状态在被构造后就是不可变的。Immutable对象在本质上是线程安全的,这种不变性由其构造器所建立,并且这种不变性将会一直保持。
Immutable objects are always thread-safe.
不可变的对象永远是线程安全的。

Immutable objects are simple. They can only be in one state, which is carefully controlled by the constructor. One of the most difficult elements of program design is reasoning about the possible states of complex objects. Reasoning about the state of immutable objects, on the other hand, is trivial.
Immutable对象非常简单。它们可能只有一个状态,而该状态由其构造器所控制。在程序设计过程中一个非常困难的点是搞清楚复杂对象的可能状态。但是,思考immutable对象的状态是没有意义的。
Immutable objects are also safer. Passing a mutable object to untrusted code, or otherwise publishing it where untrusted code could find it, is dangerous the untrusted code might modify its state, or, worse, retain a reference to it and modify its state later from another thread. On the other hand, immutable objects cannot be subverted in this manner by malicious or buggy code, so they are safe to share and publish freely without the need to make defensive copies [EJ Item 24].
Immutable对象也是安全的。将可变对象传递给不可信赖的代码或者使得不可信赖的号码可以访问到可变对象的时候是很危险的,因为这些不可信赖的代码可能会修改可变对象的状态,还有更可怕的情况:通过保留一个对该对象应用使得后续的线程可能会修改该对象。但是,immutable对象并不存在被恶意的、错误的方式修改的可能。因此这样的对象可以自由的被共享或者公开,而不需要做defensive复制。
Neither the Java Language Specification nor the Java Memory Model formally defines immutability, but immutability is not equivalent to simply declaring all fields of an object final. An object whose fields are all final may still be mutable, since final fields can hold references to mutable objects.
无论是Java语言规范和JMM都没有针对immutability给出一个明确的定义。但是immutability并不是简单的将所有的对象域都声明为final类型的。一个所有域都是final的对象仍然可能是可变的,因为fianal域可能包含对可变对象的应用。
An object is immutable if:
• Its state cannot be modifled after construction;
• All its flelds are final;[12] and
• It is properly constructed (the this reference does not escape during construction).
所有的状态在构造后无法被修改。
所有的域都是final的。
被良好的构造(this应用在构造的过程中不会逃逸)

[12] It is technically possible to have an immutable object without all fields being final。 String is such a class but this relies on delicate reasoning about benign data races that requires a deep understanding of the Java Memory Model. (For the curious: String lazily computes the hash code the first time hashCode is called and caches it in a nonfinal field, but this works only because that field can take on only one nondefault value that is the same every time it is computed because it is derived deterministically from immutable state. Don't try this at home.)
在不是所有域都是final的情况下构造一个immutable对象同样是可行的。String类就是这样一个类,但是这会依赖于对数据竞争的良好理解,这种理解需要对java内存模型的深入研究。(String将会在hashcode第一次被调用的时候延迟计算hash code,然后将其缓存在一个非final域中。这种做法能够实现仅仅是因为该域只有在一个非默认的的值在每次计算都相同的情况下才会有价值,因为该值是由追溯其不可变状态而获得的,不要随便使用这种模式)
Immutable objects can still use mutable objects internally to manage their state, as illustrated by ThreeStooges in Listing 3.11. While the Set that stores the names is mutable, the design of ThreeStooges makes it impossible to modify that Set after construction. The stooges reference is final, so all object state is reached through a final field. The last requirement, proper construction, is easily met since the constructor does nothing that would cause the this reference to become accessible to code other than the constructor and its caller.
Immutable对象中仍然可能在其内部包含可变对象来管理其状态。尽管保存名字的Set是可变的,ThreeStooges类的设计使得在其被构建之后,Set就不可能会被修改。Stooges的应用是final的,这样一来,所有的对象状态只能通过一个final域来访问的要求就实现了。最后一点,良好的构建也已经被实现了,构造器并没有将this应用公开给其他代码。
Listing 3.11. Immutable Class Built Out of Mutable Underlying Objects.
@Immutable
public final class ThreeStooges {
    private final Set<String> stooges = new HashSet<String>();

    public ThreeStooges() {
        stooges.add("Moe");
        stooges.add("Larry");
        stooges.add("Curly");
    }

    public boolean isStooge(String name) {
        return stooges.contains(name);
    }
}

Because program state changes all the time, you might be tempted to think that immutable objects are of limited use, but this is not the case. There is a difference between an object being immutable and the reference to it being immutable. Program state stored in immutable objects can still be updated by "replacing" immutable objects with a new instance holding new state; the next section offers an example of this technique.[13]
[13] Many developers fear that this approach will create performance problems, but these fears are usually unwarranted. Allocation is cheaper than you might think, and immutable objects offer additional performance advantages such as reduced need for locking or defensive copies and reduced impact on generational garbage collection.
由于代码的状态一直在不断的改变,你可能会认为immutable对象必须被有限度的使用,事实并非如此。一个对象时immutable的和对该对象的应用是immutable是由区别的。保存在immutable对象中的程序状态仍然有可能通过更改一个保存新状态的immutable对象而被修改。下一节中将会展现该技术。
很多开发者害怕这种做法可能会导致性能问题,但是这种担心是没有依据的。对对象的分配比你想象的代价更低,而且immutable对象可以提供额外的性能优势例如减少对锁的使用以及defensive copy。并且可以减少连锁的垃圾回收机制的冲击。
3.4.1. Final Fields(final域)
The final keyword, a more limited version of the const mechanism from C++, supports the construction of immutable objects. Final fields can't be modified (although the objects they refer to can be modified if they are mutable), but they also have special semantics under the Java Memory Model. It is the use of final fields that makes possible the guarantee of initialization safety (see Section 3.5.2) that lets immutable objects be freely accessed and shared without synchronization.
Final关键字是C++中常量机制的一种受限版本,Final关键字可以用来支持immutable对象的构造。Final域是不能被修改的(虽然他所引用的对象可能被修改),但是final域在java内存模型下有其独特的语法。Final域的用处就在于对初始化安全性的保证成为可能,这种可能性使得immutable对象在无需同步机制的情况下可以被安全的访问和共享。
Even if an object is mutable, making some fields final can still simplify reasoning about its state, since limiting the mutability of an object restricts its set of possible states. An object that is "mostly immutable" but has one or two mutable state variables is still simpler than one that has many mutable variables. Declaring fields final also documents to maintainers that these fields are not expected to change.
即使某个对象是可变的,使得其某些域变成final的也可以简化对其状态的管理,因为限制对象的可变性就意味着限制了对象状态的集合。一个“大部分不可变”只有一个或两个可变状态的变量的对象仍然比含有很多可变变化的对象简单。将某个域声明为final也同样可以告诉该对象的维护者应该不要将该域修改。
Just as it is a good practice to make all fields private unless they need greater visibility [EJ Item 12], it is a good practice to make all fields final unless they need to be mutable.
在不需要更高可见性的情况下,将所有的域都变成是private是一个很好的实践,除非你想获得可变性,将所有域都变成final是一个很好的实践。


3.4.2. Example: Using Volatile to Publish Immutable Objects(使用volatile公开Immutable对象)
In UnsafeCachingFactorizer on page 24,we tried to use two AtomicReferences to store the last number and last factors, but this was not thread-safe because we could not fetch or update the two related values atomically. Using volatile variables for these values would not be thread-safe for the same reason. However, immutable objects can sometimes provide a weak form of atomicity.
在UnsafeCachingFactorizer类中,我们曾经尝试使用两个AtomicReferences来保存最新的数值和最新的因子,但这不是线程安全的,因为我们无法通过原子的获取或修改这两个值。同样的原因,使用对这些值使用volatile类型的变量同样是不安全的,但是Immutable对象可以提供一种弱形式的原子性。
The factoring servlet performs two operations that must be atomic: updating the cached result and conditionally fetching the cached factors if the cached number matches the requested number. Whenever a group of related data items must be acted on atomically, consider creating an immutable holder class for them, such as OneValueCache[14] in Listing 3.12.
[14] OneValueCache wouldn't be immutable without the copyOf calls in the constructor and getter. Arrays.copyOf was added as a convenience in Java 6; clone would also work.
因式分解servlet执行的两个操作必须是原子的,修改缓存值,如果缓存的值命中请求值的话获得缓存的因数。无论如何一组相关的数据项必须被原子性的起作用。可以考虑创建一个Immutable的对象来保持他们例如OnValueCache。
Race conditions in accessing or updating multiple related variables can be eliminated by using an immutable object to hold all the variables. With a mutable holder object, you would have to use locking to ensure atomicity; with an immutable one, once a thread acquires a reference to it, it need never worry about another thread modifying its state. If the variables are to be updated, a new holder object is created, but any threads working with the previous holder still see it in a consistent state.
存在于对多个相关变量的访问和升级场景中的条件竞争可能通过使用Immutable对象来保存这些变量来缓解。在一个可变对象中保持变量,你必须使用锁机制来保证原子性,在Immutable中,即使线程获得了对该对象的应用,你也不必担心其他线程可能会修改这种状态。如果变量需要被修改,一个新的保存对象需要被创建,但是所有其他使用上一个保存对象的线程仍然可以看到一致的状态。
Listing 3.12. Immutable Holder for Caching a Number and its Factors.
@Immutable
class OneValueCache {
    private final BigInteger lastNumber;
    private final BigInteger[] lastFactors;

    public OneValueCache(BigInteger i,
                         BigInteger[] factors) {
        lastNumber  = i;
        lastFactors = Arrays.copyOf(factors, factors.length);
    }

    public BigInteger[] getFactors(BigInteger i) {
        if (lastNumber == null || !lastNumber.equals(i))
            return null;
        else
            return Arrays.copyOf(lastFactors, lastFactors.length);
    }
}

VolatileCachedFactorizer in Listing 3.13 uses a OneValueCache to store the cached number and factors. When a thread sets the volatile cache field to reference a new OneValueCache, the new cached data becomes immediately visible to other threads.
Listing3.13中的VolatileCachedFactorizer对象使用OneValueCache来保存被缓存的值和因数。当一个线程将volatile缓存与设置为一个新的OneValueCache,新的缓存数据就会立刻变得对其他线程可变。
The cache-related operations cannot interfere with each other because One-ValueCache is immutable and the cache field is accessed only once in each of the relevant code paths. This combination of an immutable holder object for multiple state variables related by an invariant, and a volatile reference used to ensure its timely visibility, allows VolatileCachedFactorizer to be thread-safe even though it does no explicit locking.
缓存相关的操作并不会互相影响,因为OneValueCache是Immutable而且缓存域每次只能使用一条路径来访问它。使用Immutable保存对象来保证多个相关状态变量的一致性;使用volatile引用来确保其时间可见性的组合使得VolatileCachedFactorizer类在没有使用到显性锁的情况下,依然能够保证线程安全。
0
0
分享到:
评论

相关推荐

    前端开源库-immutability-helper

    **前端开源库-immutability-helper** 是一个专为JavaScript开发者设计的工具库,它提供了一种高效、方便的方式来处理对象和数组的不变性。在JavaScript中,直接修改对象或数组通常会导致不可预测的行为,因为它们是...

    immutability-helper-extensions:扩展不变性助手

    安装带yarn : yarn add immutability-helper immutability-helper-extensions使用npm : npm i --save immutability-helper immutability-helper-extensions添加扩展要导入扩展,只需导入即可: const update = ...

    string-immutability:Java字符串不变性和StringBuilder不变性的单元测试。 String和StringBuilder是两个与文本处理相关的流行类

    在`string-immutability-master`这个项目中,可能包含了这样的测试用例,通过Junit或其他测试框架,来演示和验证Java字符串不变性以及`StringBuilder`的可变性。测试代码通常会包括创建、修改和比较字符串的不同方法...

    Java+9+Programming+By+Example-Packt+Publishing(2017).pdf

    Immutability was the norm here. However, I wondered how traditional algorithms would look in a functional setting and started learning about it. A data structure is never mutated in place. Instead, a...

    immutability:使实例不可变(深度冻结)并进行版本控制

    不变性 使实例不可变(深度冻结)并进行版本控制。 前言 该项目是宝石的一个克隆,但在实现上存在一些差异: 它使用 gem深度冻结实例。 而不是存储更改实例的过程,它存储对先前状态和当前版本号的引用。 这种将...

    Laravel开发-immutability

    总的来说,"Laravel开发-immutability"这个主题为Laravel开发者提供了一种工具,帮助他们更轻松地实现模型属性的不可变性,从而提升应用的数据安全性和一致性。在处理关键数据或有严格数据变更规则的项目中,这个包...

    immutability-skinable-component:不变性皮肤成分

    immutability-skinable-component ##问题 通用UI组件的皮肤管理,怎样一个管理方式比较优秀? UI组件的扩展性怎样来保证? 如何在保证扩展性的同时还能让整个组件结构变得更加优雅? react组件的性能该如何提升? ##...

    react-immutability-techniques

    在React开发中,数据不变性是一项重要的优化策略,它能够帮助我们提高应用性能,避免不必要的渲染,同时使得代码更容易理解和维护。"react-immutability-techniques"这个主题主要涉及如何在React应用中有效地实现...

    my-git_immutability

    参考:React immutability比immutable更简洁的数据不可变更新库2018.12.24 07:44 1610浏览immutability-helper因React官方出镜,而被纳入后宫引言之前项目中遇到数据拷贝、引用之间数据层级嵌套过深,拷贝的值相互...

    immutability-helper:在不更改原始源的情况下变异数据副本

    不变性的帮助者 更改数据副本而不更改原始源 通过NPM设置 npm install immutability-helper --save 这是对替代: // import update from 'react-addons-update'; import update from 'immutability-helper' ; ...

    Go-hamt.go提供Go中的不变和高效率内存使用的Maps与Sets

    "Go-hamt.go"项目致力于提供一种实现,它为Go程序员提供了不变性(immutability)和高效内存使用的Map与Set数据结构。这些数据结构基于哈希映射数组(Hash Array Mapped Trie,简称HAMT),是一种在键值对存储中实现...

    三张图彻底了解Java中字符串的不变性

    在Java编程语言中,字符串的不变性(Immutability)是一个关键特性,它指的是字符串对象一旦创建后,其内容就不能被修改。这个概念对于理解和优化Java程序至关重要,尤其是在处理字符串操作时。以下将通过三张图来...

    object-path-immutable:修改深层对象属性而不修改原始对象(不变性)。 非常适合React和Redux

    小型JS库,无需修改原始对象即可修改深层对象的属性(不变性)。 与React(特别是在使用setState() )和Redux(在reducer内部)配合使用时效果很好。 这可以看作是React Immutability Helpers和Immutable.js的一种...

    21-C-ImmutableObject-Code.zip

    内部不变性(Intrinsic Immutability)指的是对象的内部状态在构造完成后不再变化。例如,一个字符串对象在创建后,其内容就不能再被修改。C#中的字符串类型就是不可变的,当你执行如`string.Concat`或`string....

    开源项目-lukechampine-freeze.zip

    在软件开发中,对象的不变性(Immutability)是一种重要的设计原则,它能带来诸多好处,如简化并发编程、提高代码可读性和安全性等。Lukechampine 创建的开源项目 "freeze" 正是专注于实现这一目标的工具,它可以将...

    学习React之前你需要知道的JavaScript基础知识

    2. 不变性(Immutability)原则在React中非常重要。在JavaScript中,理解数据不可变的概念有助于我们更好地管理状态,避免不必要的数据更新导致的渲染问题。 3. 高阶函数(Higher-order functions)是指那些以其他...

    ReactUtilsDemo:React相关插件,效果以及工具用法讲解的Demo

    基本不变性 详细介绍了immutability-helper插件的基本用法和注意事项。 更多详细请查看: React组件生命周期 详细介绍了React生命周期各个阶段的执行顺序。 更多信息请查看: redux-devtools-demo 简单介绍了redux

    transit-java-0.8.269.zip

    yaidom是"Yet Another Immutable DOM"的缩写,它是一个用Java编写的XML DOM实现,强调不变性(immutability)和灵活性。不变性意味着一旦创建了XML文档对象,就不能再对其进行修改,这有助于代码的并发处理和调试,...

    Node.js-Immutabilityinunderonekilobyte

    2. **浅拷贝与深拷贝**:理解何时使用浅拷贝(只复制第一层属性)和深拷贝(递归复制所有嵌套属性)来确保数据的不变性。 3. **Object.freeze**:如何利用JavaScript内置的`Object.freeze`方法阻止对象的属性被修改...

    深入理解C#中的String

    1. 不变性(Immutability): C#中的String类具有不可变性,这意味着一旦一个字符串被创建,就不能改变它的内容。例如,当你执行`str2 += "change"`这样的操作时,实际上不是在原字符串上进行修改,而是创建了一个新...

Global site tag (gtag.js) - Google Analytics