原文链接:http://tutorials.jenkov.com/java-concurrency/thread-safety-and-immutability.html
摘要:这是翻译自一个大概30个小节的关于Java并发编程的入门级教程,原作者Jakob Jenkov,译者Zhenning Lang,转载请注明出处,thanks and have a good time here~~~(希望自己不要留坑)
竞争只发生在多个线程写相同资源的时候,如果仅仅是多个线程读取同一个资源,则不会发生竞争。
那么可以通过使共享对象保持不变(immutable)来让使用它的线程无法更新这个对象,从而达到线程安全,例如:
public class ImmutableValue{
private int value = 0;
public ImmutableValue(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
}
上例中在构造函数中给 value 赋值,而由于没有 setter 方法,value 的值也无法被改变。一旦 ImmutableValue 的实例被创建,其 value 就保持不变,我们称之为具有不变性。
如果需要对 ImmutableValue 的实例进行一些操作,那么可以通过返回一个具有操作后结果的新的实例来实现不变性,下例展示了 add 操作是如何保持不变性的:
public class ImmutableValue{
private int value = 0;
public ImmutableValue(int value){
this.value = value;
}
public int getValue(){
return this.value;
}
public ImmutableValue add(int valueToAdd){
return new ImmutableValue(this.value + valueToAdd);
}
}
请仔细分析 add() 方法是如何通过返回一个新的 ImmutableValue 实例保持不变性的。
实例的引用是不安全的(The Reference is not Thread Safe)!
非常值得注意的一点是,即便一个对象本身是具有不变性并且线程安全的,对这个对象的引用可能并不是线程安全的。例如:
public class Calculator{
private ImmutableValue currentValue = null;
public ImmutableValue getValue(){
return currentValue;
}
public void setValue(ImmutableValue newValue){
this.currentValue = newValue;
}
public void add(int newValue){
this.currentValue = this.currentValue.add(newValue);
}
}
Calculator 类包含一个 ImmutableValue 实例的引用。如果仔细分析 setValue() 和 add() 方法,我们可以发现虽然 ImmutableValue 类本身是具有不变性的,但 Calculator 类却不具有不变性,也并非线程安全的。换言之,虽然具有不变性的类本身是线程安全,但对其引用的使用却不一定是线程安全的。这是想通过不变性达到线程安全目的所需要牢记的事。
为了使 Calculator 类变得线程俺去,可以将 getValue(), setValue(), 和 add() 方法声明成同步的(synchronized)。