在Java Concurrency In Practice下面的示例中,将说明如何创建不可变类:
http://www.javaconcurrencyinpractice.com/listings/ThreeStooges.java
该类具有:private final Set<String> stooges = new HashSet<String>();在其构造函数中初始化:
public ThreeStooges() {
stooges.add("Moe");
stooges.add("Larry");
stooges.add("Curly");
}
Run Code Online (Sandbox Code Playgroud)
并有一个方法
public boolean isStooge(String name) {
return stooges.contains(name);
}
Run Code Online (Sandbox Code Playgroud)
看一个名字是否是三个傀儡之一.
但是当我这样做时ThreeStooges ts = new ThreeStooges(),是否可以保证stooges在引用设置之前对象将被正确构造(即正确初始化的状态)ts?
换句话说,如果我发布这个对象,是否有可能某些线程会将其视为错误初始化(即stooges通过访问时它会看到为空isStooge())?
我的理解是,一个不可变对象将被正确构造并在发布时正确可见 - (因为它使用最终实例变量).我的理解是否正确?如果是,这个类仍然是不可变的吗?
编辑:从我看到的评论看来,在构造函数完成之前,很难相信其他线程可以看到对象.这是一个链接:http://jeremymanson.blogspot.in/2008/05/double-checked-locking.html
小智 10
这里有一大堆错误的答案:(
Java内存模型中最终字段的初始化安全保证非常强大.它们不仅保证写入到最后字段在构造是,其获得一个共享的参照对象(即使通过数据种族获得的参考)的任何线程可见的,但它们保证在构造任何写入通过该通过该引用读取引用是可见的.唯一需要注意的是,施工期间对建筑物的引用不会逃脱.当然,如果类在构造之后要改变对象,或者为客户提供一种方法来获取HashSet的对象引用,那么所有的赌注都会被取消.
此保证的目的是防止需要对不可变(在这种情况下,实际上是不可变的)对象的状态进行棘手的推理.如果该字段是最终的并且除了构造函数中的那些之外没有对引用对象的状态的写入,那么您就完成了.
如果这让你的头部受伤,请不要担心.如果你(a)使引用字段为private和final,并且(b)不修改构造函数之外的引用对象的状态,并且(c)不提供任何允许客户端执行相同操作的访问(例如,没有变异的方法,没有暴露场的吸气剂等),你已经完成了.
| 归档时间: |
|
| 查看次数: |
229 次 |
| 最近记录: |