Java并发编程(Java Concurrency)(10)- 线程安全与不变性(Thread Safety and Immutability)

时间:2021-06-17 06:59:32

原文链接: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)。