Concurrence-9-Thread-Safety-and-Immutability


Thread Safety and Immutability


##### 线程安全和不可变性

文章的地址:翻译文章的源地址
竞争条件只有在多个线程访问相同的资源,以及一个或多个线程写入资源时才会出现。 如果多个线程读取相同的资源竞争条件是不发生。我们可以确保线程之间共享对象 不更新以便使共享对象不变,从而线程安全的。下面是一个示例:

public class ImmutableValue{
  private int value = 0;
  public ImmutableValue(int value){
    this.value = value;
  }
  public int getValue(){
    return this.value;
  }
}

备注:ImmutableValue实例的值传递给构造函数。注意到没有setter方法设置这个值。 也就是说 ImmutableValue实例创建后不能更改其值。它是不可变的。 然而你可以使用getValue()方法获取它的值。

如果你需要操作ImmutableValue实例的值,你可以在操作运算后返回一个新的实例,下面就是add的方法:

 public ImmutableValue add(int valueToAdd){
      return new ImmutableValue(this.value + valueToAdd);
      }

备注:add方法直接返回了一个实例,并且构造函数中接受的是加操作之后的值,而不是返回value所在的实例。

引用不是线程安全的
如果对象是不变的,那么它是线程安全的,但是对于它的引用可能不是线程安全的,见下例:

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方法你能够改变引用值, 所以这个引用本身不是不可变的,所以它不是线程安全的。换句话说,就是不可变的类是线程安全的,但是对他的引用不是的。在通过不变形保证 线程安全时,需要记住这一点。

如果想要Calculator这个类线程安全,你可以声明getValue(), setValue(), and add()是同步方法。



上一篇  Concurrence-10-Java Memory Model 下一篇   Concurrence-8-Thread Safety and Shared Resources