满足同步需求的另一种方法是使用不可变对象。许多时候出现并发问题都是与多线程试图同时访问同一个可变的状态相关。如果对象的状态不会改变,那么这些问题与复杂性也就自然消失了。
如果某个对象在被创建后其状态就不能被改变,那么这个对象就称为不可变对象。线程安全性是不可变对象的固有属性之一,它们的不变性条件是由构造函数创建的,只要它们的状态不改变,那么这些不变性条件就能得以维持。
[b]不可变对象一定是线程安全的。[/b]
不可变性不等于将对象中所有的域都声明为final类型,即使对象中所有的域都是final类型的,这个对象也仍然是可变的,因为在final类型的域中可以保存对可变对象的引用。
[b]
当满足以下条件的时候,对象才是不可变的:
1、对象创建以后其状态就不能修改;
2、对象的所有域都是final类型;
3、对象是正确创建的;
[/b]
final类型的域是不能修改的(但是如果域所引用的对象是可变的,那么这些被引用的对象是可以修改的)。然而,在Java内存模型中,final域还有着特殊的语义。final域能确保初始化过程的安全性,从而可以不受限制的访问不可变对象,并在共享这些对象时无需同步。
如果某个对象在被创建后其状态就不能被改变,那么这个对象就称为不可变对象。线程安全性是不可变对象的固有属性之一,它们的不变性条件是由构造函数创建的,只要它们的状态不改变,那么这些不变性条件就能得以维持。
[b]不可变对象一定是线程安全的。[/b]
不可变性不等于将对象中所有的域都声明为final类型,即使对象中所有的域都是final类型的,这个对象也仍然是可变的,因为在final类型的域中可以保存对可变对象的引用。
[b]
当满足以下条件的时候,对象才是不可变的:
1、对象创建以后其状态就不能修改;
2、对象的所有域都是final类型;
3、对象是正确创建的;
[/b]
import java.util.HashSet;
import java.util.Set;
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);
}
}
final类型的域是不能修改的(但是如果域所引用的对象是可变的,那么这些被引用的对象是可以修改的)。然而,在Java内存模型中,final域还有着特殊的语义。final域能确保初始化过程的安全性,从而可以不受限制的访问不可变对象,并在共享这些对象时无需同步。