我知道这显然是一个竞争条件。但是可能发生哪些事情呢?
class Blah {
List<String> stuff;
public List<String> getStuff() {
return stuff
}
public void setStuff(List<String> newValue) {
this.stuff = newValue
}
}
b = new Blah();
// Thread one
b.setStuff(getListFromSomeNetworkResource());
for (String c : b.getStuff()) {
// Work with c
}
// Thread two
b.setStuff(getListFromSomeNetworkResource());
for (String c : b.getStuff()) {
// Work with c
}
- 这会抛出运行时异常吗?
- 这个段错误 jvm 可以吗?
- 这个段错误可以错误之一的线程吗?
- 是否取决于处理器。如果是英特尔至强处理器怎么办?
- 这会引发空指针异常吗? 线程
- 2 可以读取线程 1 设置的内容,反之亦然,如果函数实际上返回了不同的值
我知道这是一个竞争条件,不会写这样的代码。但是我如何说服别人不要这样做呢?
更新:
假设:
getListFromSomeNetworkResource()
总是返回一个新的ArrayList
。大小可以是 0 或更大。getListFromSomeNetworkResource()
是线程安全的。
这会抛出 RuntimeException 吗?
否,如果getListFromSomeNetworkResource()
是线程安全的并且不返回null
.
这个段错误 jvm 可以吗?
这个段错误可以错误之一的线程吗?
是否取决于处理器。如果是英特尔至强处理器怎么办?
不。
这会引发空指针异常吗?
只有当getListFromSomeNetworkResource()
可以返回null
.
2 可以读取线程 1 设置的内容,反之亦然,如果函数实际上返回了不同的值
是的,这很可能会发生。
危险是这样的顺序:
- 主题一:
b.setStuff(getListFromSomeNetworkResource());
- 主题二:
b.setStuff(getListFromSomeNetworkResource());
- 线程一:
b.stuff.iterator()
(通过b.getStuff()
,在for循环的开头(
在这种情况下,线程 1可能正在迭代线程 2 设置的列表。该发布,从线程二到线程一,是在没有任何同步的情况下完成的 - 这是一场数据竞赛。假设该列表本身不是线程安全的,则可能会发生很多事情。主要问题是,由于数据竞争,列表的某些状态对线程一可见,但不是全部。
- 它可能会抛出一些运行时异常。例如,也许一个字段认为由于调整大小,列表具有
n
元素。但是来自该调整大小的新数组并没有结束,因此您最终会得到一个 ArrayIndexOutOfBoundsException - 它可能出于多种原因抛出 NullPointerException;也许它是一个链表,其中一个引用写入没有进入线程
它不应该导致任何段错误:这些错误只能来自 JVM 中的错误,但永远不会来自代码中的错误。
它可能取决于处理器,因为处理器可能有不同的处理方式,例如将内存从一个 CPU 缓存刷新到另一个 CPU 缓存 - 这是不安全发布可能导致您只能看到一个线程从另一个线程写入的一些数据的原因之一。有一些方法可以强制刷新这些缓存;在 Java 中指定它们的方法是通过各种数据同步机制(获取锁、使用易失字段等(。