Class Future
{
private volatile boolean ready;
private Object data;
public Object get()
{
if(!ready) return null;
return data;
}
public synchronized void setOnce(Object o)
{
if(ready) throw...;
data = o;
ready = true;
}
}
它说“如果一个线程读取数据,则从写入到读取存在一个先发生边缘,以保证数据的可见性”
从我的学习中我知道:
- volatile 确保每次读/写都在内存中,而不仅仅是在缓存或寄存器中;
- volatile 确保重新排序:也就是说,在 setOnce() 方法中 data = o 只能安排在 if(ready) throw... 之后,并且在 ready = true 之前;这保证如果在 get() ready = true 中,数据必须为 o。
我的困惑是
是否有可能当线程 1 在 setOnce() 中时,到达 data = o 之后的点;准备好之前=真;同时线程2运行get(),read ready为false,返回null。并且 thead 1 继续准备好 = true。在这种情况下,线程 2 没有看到新的“数据”,即使数据已在线程 1 中分配了新值。
get() 不同步,这意味着同步锁无法保护 setOnce(),因为线程 1 调用 get() 不需要获取锁来访问变量就绪数据。所以线程不能保证看到最新的数据值。我的意思是锁只保证同步块之间的可见性。即使一个线程正在运行同步块 setOnce(),另一个线程仍然可以进入 get() 并在不阻塞的情况下访问就绪和数据,并且可能会看到这些变量的旧值。
在 get() 中,如果 ready = true,则数据必须为 o?我的意思是这个线程可以保证看到数据的可见性?我认为 data 不是 volatile 也不是 get() 同步的。这个线程是否可以看到缓存中的旧值?
谢谢!