【发布时间】:2013-05-03 12:09:06
【问题描述】:
我想编写一个简单的线程安全类,可以用来设置或获取整数值。
最简单的方法是使用同步关键字:
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 关键字的类不是 thread-safe 并且以下顺序也是可能的:
- 线程 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 并发实践一书的片段:
"原子变量的读写具有相同的内存语义 作为 volatile 变量。"
编写线程安全 MyIntegerHolder 的最佳(最好是非阻塞)方式是什么?
如果你知道答案,我想知道你为什么认为它是正确的。它是否遵循规范?如果有,怎么做?
【问题讨论】:
-
我还在学习,如果有人能向我澄清一件事,那就太好了。
synchronized或volatile关键字如何使它更加线程安全?由于整数赋值和读取本身是原子的,它会改变什么吗?这种方法无论如何都不允许原子增量或获取和设置。谢谢 -
@Sebi 线程安全是一个在两个或多个线程中运行的程序,没有一个线程干扰另一个线程。您可以通过不同的方式/技术解决这个问题,一个线程干扰另一个线程。一个简单的 int x = x + x 似乎是原子的,但不是(更多关于这个,搜索 volatile 和 atomic)! “让它更加线程安全”,只是解决问题的一种方法。这不会使更多线程安全,只是解决相同问题的不同实现。
-
@ThufirHawat 我知道什么是线程安全程序,或者添加涉及在写入之前进行多次读取,但我确信这门课有一些我不知道的东西。我无法理解如何使用暴露整数的 getter 和 setter 的类来执行任何需要线程安全而不被外部锁定的事情(
Integer就足够了)。
标签: java multithreading concurrency java-memory-model