线程安全和不可变性

竞态之发生在多线程访问相同的资源,同时有一个或多个线程写入东西到资源。相反,如果是多线程读取资源的话,反而不会发生竞态。比如

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

一旦 ImmutableValue 实例创建,你就不能改变它的值。ImmutableValue 是不可变的。你能做的只有通过 getValue() 读取它的值。

如果你要对 ImmutableValue 进行操作,可以通过返回一个新的 ImmutableValue 实例来实现,比如

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);
  	}
}

引用不是线程安全的!

有一点很重要,即使一个对象是不可变、线程安全的,指向对象的引用也许不是线程安全的。比如这个例子

public class Calculator {
  	private ImmutableValue currentValue = null;
  
  	public ImmutableValue getValue() {
      	return currValue;
  	}
  
  	public void setValue(ImmutableValue newValue) {
      	this.currentValue = newValue;
  	}
  	
  	public void add(int newValue) {
      	this.currentValue = this.currentValue.add(newValue);
  	}
}

Calculator 类持有 ImmutableValue 的实例。可以通过 setValue()add() 方法改变引用。因此,即使Calculator 类在内部持有了 ImmutableValue 对象,也不是它自己的 ImmutableValue 对象了,因此 Calculator 不是线程安全的。换一种方法来说:ImmutableValue 是线程安全的,但是 ImmutableVlue 的使用不是线程安全的。当尝试通过不可变性实现线程安全时,这点需要牢记。

要实现 Calculator 线程安全,可以声明 getValue()setValue()add()synchronized

posted @ 2016-09-22 22:49  勇敢的少年啊  阅读(178)  评论(0编辑  收藏  举报