本文主要是介绍线程安全和不可变性(Thread Safety and Immutability),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
原文链接:http://tutorials.jenkov.com/java-concurrency/thread-safety-and-immutability.html
竞争条件只会在多个线程访问相同的资源并且一个或多个线程改写这个资源的情况下发生。如果多个线程只是同时读取相同的资源不会导致竞争条件的发生。
我们可以通过某种手段让共享的对象不可改变,从而可以确保这些不可改变的共享对象不会被任何一个线程改变,因此这些不可改变的对象是线程安全的。下面是一个例子:
public class ImmutableValue {private int value = 0;public Immutablevalue(int value) {this.value = value;}public int getValue() {return this.value;}}
注意,ImmutableValue 类的实例的值是通过构造方法传递的、 ImmutableValue 类是没有 set 方法的,一旦 ImmutableValue 类的实例被创建以后就不能改变它的值。 ImmutableValue 类的实例是不可改变的,可以通过 getValue() 方法来读取它的值。
如果需要在这个 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() 方法用 add 操作的结果重新构造了一个 ImmutableValue 类的实例并返回,而不是直接对原来的不可变对象的值 value 做 add 操作。
引用不是线程安全的!
记住,即使一个对象是不可变的因此这个对象是线程安全的,但这个对象的引用未必是线程安全的。看下面的例子:
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 类在内部使用了一个不可变的对象,但并不是说这个 Calculator 类就不可改变,它还是线程不安全的。换句话说, ImmutableValue 类是线程安全的,但使用了这个类的类未必也是线程安全的。这是通过不可变性来达到线程安全时需要注意的问题。
为了使 Calculator 类达到线程安全,可以在 getValue()、 setValue() 和 add() 方法前声明为 synchronized 方法。声明为 synchronized 方法消除了这个问题。
Next: Java 内存模型
这篇关于线程安全和不可变性(Thread Safety and Immutability)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!