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;
}
}
它说"如果一个线程读取数据,那么从写入到读取的前沿发生的边缘保证了数据的可见性"
我从学习中知道:
我的困惑是
当线程1在setOnce()中时,可能到达data = o之后的点;在ready = true之前;同时,线程2运行到get(),read ready为false,并返回null。并且thead 1继续准备= true。 在这种情况下,线程2没有看到新的"数据"即使数据已在主题1中分配了新值。
get()没有同步,这意味着同步锁无法保护setOnce(),因为线程1调用get(),它不需要获取锁来访问变量就绪数据。所以线程不能保证看到最新的数据值。通过这个,我的意思是锁只保证同步块之间的可见性。即使一个线程正在运行synchronized block setOnce(),另一个线程仍然可以进入get()并访问ready和data而不会阻塞,并且可能会看到这些变量的旧值。
,如果ready = true,数据必须是o?我的意思是这个线程可以保证看到数据的可见性?我认为数据不是易失性的,也不是get()同步的。该线程是否可以在缓存中看到旧值?
谢谢!
答案 0 :(得分:2)
volatile确保每次读/写都在内存中,而不仅仅在缓存或寄存器中;
不。它只是确保它对其他线程可见。在现代硬件上,不需要访问内存。 (这是一件好事,主要记忆很慢。)
volatile确保重新排序:也就是说,在setOnce()方法中,data = o只能在if(ready)throw ...之后和ready = true之前调度;这保证了如果在get()ready = true中,数据必须是o。
那是对的。
当线程1在setOnce()中时,可能到达data = o之后的点;在ready = true之前;同时,线程2运行到get(),read ready为false,并返回null。并且thead 1继续准备= true。在这种情况下,线程2没有看到新的"数据"即使数据已在线程1中分配了新值。
是的,但如果这是一个问题,那么你就不应该使用这样的代码。据推测,此代码的API将保证get
在setOnce
返回后调用时保证看到结果。显然,您无法保证get
会在我们完成制作之前看到结果。
get()没有同步,这意味着同步锁不能保护setOnce(),因为线程1调用get(),它不需要获取锁以访问变量就绪数据。所以线程不能保证看到最新的数据值。通过这个,我的意思是锁只保证同步块之间的可见性。即使一个线程正在运行synchronized block setOnce(),另一个线程仍然可以进入get()并访问ready和data而不会阻塞,并且可能会看到这些变量的旧值。
没有。如果这是真的,那么几乎不可能使用同步。例如,常见的模式是创建一个对象,然后获取集合上的锁并将该对象添加到集合中。如果获取集合上的锁定并不能保证创建对象所涉及的写入是可见的,那么这将无法工作。
在get()中,如果ready = true,数据必须是o?我的意思是这个线程可以保证看到数据的可见性?我认为数据不是易失性的,也不是get()同步的。该线程是否可以在缓存中看到旧值?
Java volatile
操作被定义为使得看到更改为1的线程保证在线程看到更改之前看到所做的所有其他内存更改。在其他语言(例如C或C ++)中则不然。这可能会使Java的易失性在某些平台上变得更加昂贵,但幸运的是并不是在典型的平台上。
另外,请不要在缓存中谈论""。这与缓存无关。这是一种常见的误解。它与可见性有关,而与缓存无关。大多数缓存提供对缓存的完全可见性(打孔" MESI协议"进入您最喜爱的搜索引擎以了解更多信息),并且不需要任何特殊内容来确保可见性。