【发布时间】:2017-01-03 23:13:14
【问题描述】:
假设我有一个这样的共享对象:
class Shared {
private Value val;
//synchronized set
public synchronized void setValue(Value val) {
if (this.val == null) {
this.val = val;
} else {
throw new IllegalStateException();
}
}
//unsynchronized get
public Value getValue() {
return this.val;
}
}
如果我有一个线程在应用程序初始化期间设置了值,在任何其他线程有机会读取它之前,并且没有任何东西再次更改该值,那么读取非同步值是否安全,或者我是否冒着其他线程永远看不到设置值的风险(因为变量不是volatile 并且不能保证被刷新到主内存)?
想象一下在设置发生在 Servlet 初始化期间的 Web 应用程序上下文中。我不知道此时是否已经创建了其他线程,因为这是容器的工作。但我认为届时将创建一个处理未来请求的线程拉取。
如果不安全,有没有一种方法可以安全地初始化值,而无需为每次读取永远付出代价,即使该值永远不会改变? IE。有没有办法只刷新一次值?
另外,这不就是这样吗?春天总是这样吗?在初始化容器时,单例上的各种不同步设置正在发生:通过 setter 注入 bean,@PostConstruct 初始化器触发等。一旦完成,请求就会被接受并且不会发生任何修改。如果这是不安全的,不是每个单例方法都需要同步吗?
【问题讨论】:
-
这不是一个愚蠢的问题,不,这不安全,除非
Value是不可变的。 -
@shmosel 是因为我列出的原因还是其他原因?即使这个值再也不会被触及?
-
描述在任何其他线程有机会阅读它之前。如何防止其他线程读取它?
-
好的,这样的 Spring 字段应该标记为
volatile,如果您需要它们是线程安全的:stackoverflow.com/a/23992532/360211 -
@weston 查看您链接的答案中的更新。他说 Spring bean 通常是开箱即用的线程安全的,并解释了原因。
标签: java spring concurrency synchronization thread-safety