不可变对象如何帮助防止竞争条件

时间:2017-05-19 05:47:56

标签: java multithreading immutability race-condition

以下是如何预防竞争条件的答案。 What is a race condition?

  

最好的方法是创造无副作用和无状态   函数,尽可能使用不可变的。但这并非总是如此   可能。所以使用java.util.concurrent.atomic,并发数据   结构,适当的同步和基于actor的并发性   帮助

这个答案说尽可能多地使用不可变量。我对不可变对象如何防止竞争条件感到困惑。

3 个答案:

答案 0 :(得分:1)

只有在允许至少一个线程写入/更改实例状态时才会出现竞争条件。 不可变实例 readonly ,其状态无法更改,因此所有线程仅读取对象的状态并查看相同的值(S)

答案 1 :(得分:0)

当“两个或多个线程...同时访问同一个内存位置,并且至少有一个访问用于写入,并且线程没有使用任何独占锁来控制它们的访问时,发生data race那个记忆。“

如果数据是不可变的,则不会有数据争用,因为可能没有写访问权。

此外,Java Memory Model guarantees

  

一旦构造了一个对象,分配给构造函数中最后一个字段的值对于所有其他线程都是可见的而没有同步。

答案 2 :(得分:0)

当计算结果取决于表达式和语句的计算顺序时,就会出现竞争条件。

如果表达式和语句的评估改变了状态,产生副作用,结果可能会有所不同。

如果代码中的所有内容都是不可变的,那么在评估表达式和语句时,状态没有变化,没有副作用。因此,评估顺序不会影响最终结果。

请考虑以下代码:

Map<String, Integer> map = Collections.singletonMap("key", 0);

public void increment() {
    int val = map.get("key);
    map.put("key", val + 1);
}

如果两个线程同时执行方法increment()的每个语句,则两者都读取相同的值0,并且都将相同的递增值1放入map。因此结果将是1

如果两个线程(偶然)连续执行所有语句,则一个线程将读取值0并将值1放入,而另一个线程将读取值1并放入值2

现在,如果地图是不可变的,并且两个线程都将执行以下方法:

public void logMap() {
    System.out.println("Key has value " + map.get("key"));
}

结果总是相同的,因为没有副作用(除了System.out.println所做的更改)影响计算。