我想编写一个简单的线程安全类,可用于设置或获取 Integer 值。
最简单的方法是使用synchronized关键字:
public class MyIntegerHolder {
private Integer value;
synchronized public Integer getValue() {
return value;
}
synchronized public void setValue(Integer value) {
this.value = value;
}
}
我也可以尝试使用volatile:
public class MyIntegerHolder {
private volatile Integer value;
public Integer getValue() {
return value;
}
public void setValue(Integer value) {
this.value = value;
}
}
带有volatile关键字的类是线程安全的吗?
考虑以下事件序列:
- 线程 A 将值设置为 5。
- 线程 B 将值设置为 7。
- 线程 C 读取该值。
它遵循 Java 语言规范
- “1”发生在“3”之前
- “2”发生在“3”之前
但我看不出如何从规范中得出“1”发生在“2”之前,所以我怀疑“1”不会 发生在“2”之前。
我怀疑线程 C 可能读取 7 或 5。我认为带有volatile关键字的类不是线程安全的,以下顺序也是可能的:
- 线程 A 将值设置为 5。
- 线程 B 将值设置为 7。
- 线程 C 读取 7。
- 线程 D 读取 5。
- 线程 C 读取 7。
- 线程 D 读取 5。
- ...
我是否正确假设带有volatile的 MyIntegerHolder 不是线程安全的?
是否可以通过使用 AtomicInteger 来制作线程安全的整数持有者:
public class MyIntegerHolder {
private AtomicInteger atomicInteger = new AtomicInteger();
public Integer getValue() {
return atomicInteger.get();
}
public void setValue(Integer value) {
atomicInteger.set(value);
}
}
?
这是 Java Concurrency In Practice 一书的片段:
“原子变量的读取和写入与 volatile 变量具有相同的内存语义。 ”
编写线程安全的MyIntegerHolder的最佳(最好是非阻塞)方法是什么?
如果你知道答案,我想知道你为什么认为它是正确的。它是否遵循规范?如果是这样,怎么做?