Java:易失性如何保证“数据"可见性?在这段代码中? [英] Java: how volatile guarantee visibility of "data" in this piece of code?

查看:214
本文介绍了Java:易失性如何保证“数据"可见性?在这段代码中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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;
    }
}

它说:如果线程读取数据,则从写入到读取的边缘会发生一定的变化,从而保证了数据的可见性"

It said "if a thread reads data, there is a happens-before edge from write to read of that guarantees visibility of data"

我从学习中学到了

  1. volatile确保每次读/写都将在内存中,而不是仅在高速缓存或寄存器中;
  2. volatile确保重新排序:也就是说,在setOnce()方法中,只能在if(ready)throw ...之后和ready = true之前安排data = o;这样可以保证,如果在get()ready = true中,则数据必须为o.

我的困惑是

  1. 是否有可能在线程1处于setOnce()中时达到data = o之后的点;在准备好之前= true;同时,线程2运行到get()中,read ready为false,然后返回null.并且thead 1继续准备就绪= true. 在这种情况下,即使在线程1中为数据分配了新值,线程2也看不到新的数据".

  1. is it possible that when thread 1 is in setOnce(), reaches the point that after data = o; before ready = true; At the same time, thread 2 runs into get(), read ready is false, and return null. And thead 1 continues ready = true. In this scenario, Thread 2 didn't see the new "data" even though data has been assigned new value in thread 1.

get()未同步,这意味着同步锁无法保护s​​etOnce(),因为线程1调用了get(),而get()不需要获取该锁即可访问变量ready,数据.因此,不能保证线程看到最新的数据值.通过这种方式,我的意思是锁只能保证同步块之间的可见性.即使一个线程正在运行同步块setOnce(),另一个线程仍可以进入get()并访问就绪数据,而不会发生阻塞,并且可能会看到这些变量的旧值.

get() isn't synchronized, that means the synchronized lock cannot protect setOnce() since thread 1 calls get() that needn't acquire the lock to access variable ready, data. So thread are not guaranteed to see the latest value of data. By this, I mean lock only guarantee the visibility between synchronized blocks. Even though one thread is running synchronized block setOnce(), another thread is still can go into get() and access ready and data without blocking and may see the old value of these variables.

在get()中,如果ready = true,则数据必须为o?我的意思是保证该线程可以看到数据的可见性?我认为数据不是易失性的,也不是get()同步的.这个线程可能会在缓存中看到旧值吗?

in get(), if ready = true, data must be o? I mean this thread is guaranteed to see the visibility of data? I think data is not a volatile nor the get() synchronized. Is this thread may see the old value in the cache?

谢谢!

推荐答案

volatile确保每次读/写都将在内存中,而不是仅在高速缓存或寄存器中;

volatile ensures that every read/write will be in the memory instead of only in cache or registers;

不.它只是确保它对其他线程可见.在现代硬件上,不需要访问内存. (这是一件好事,主内存很慢.)

Nope. It just ensures it's visible to other threads. On modern hardware, that doesn't require accessing memory. (Which is a good thing, main memory is slow.)

volatile确保重新排序:也就是说,在setOnce()方法中,只能在if(ready)throw ...之后和ready = true之前调度data = o;这样可以保证,如果在get()ready = true中,则数据必须为o.

volatile ensures reorder: that is, in setOnce() method data = o can only be scheduled after if(ready) throw..., and before ready = true; this guarantee that if in get() ready = true, data must be o.

是的.

当线程1在setOnce()中时,是否有可能到达data = o之后;在准备好之前= true;同时,线程2运行到get()中,read ready为false,然后返回null.并且thead 1继续准备就绪= true.在这种情况下,即使在线程1中为数据分配了新值,线程2也看不到新的数据".

is it possible that when thread 1 is in setOnce(), reaches the point that after data = o; before ready = true; At the same time, thread 2 runs into get(), read ready is false, and return null. And thead 1 continues ready = true. In this scenario, Thread 2 didn't see the new "data" even though data has been assigned new value in thread 1.

是的,但是如果这是一个问题,那么您不应该使用这样的代码.据推测,此代码的API将确保在setOnce返回之后调用get可以看到结果.显然,您不能保证get在完成制作之前就可以看到结果.

Yes, but if that's a problem, then you shouldn't be using code like this. Presumably, the API for this code would be that get is guaranteed to see the result if called after setOnce returns. Obviously, you can't guarantee that get will see the result before we're finished making them.

get()未同步,这意味着同步锁无法保护s​​etOnce(),因为线程1调用了get(),而该get()不需要获取锁即可访问变量就绪数据.因此,不能保证线程看到最新的数据值.通过这种方式,我的意思是锁只能保证同步块之间的可见性.即使一个线程正在运行同步块setOnce(),另一个线程仍然可以进入get()并在不阻塞的情况下访问ready和数据,并且可能会看到这些变量的旧值.

get() isn't synchronized, that means the synchronized lock cannot protect setOnce() since thread 1 calls get() that needn't acquire the lock to access variable ready, data. So thread are not guaranteed to see the latest value of data. By this, I mean lock only guarantee the visibility between synchronized blocks. Even though one thread is running synchronized block setOnce(), another thread is still can go into get() and access ready and data without blocking and may see the old value of these variables.

不.如果这是真的,那么同步将几乎无法使用.例如,一种常见的模式是创建一个对象,然后获取对集合的锁定,然后将该对象添加到集合中.如果获取对集合的锁不能保证创建对象时涉及到的写操作是可见的,那么这将是行不通的.

No. And if this were true, synchronization would be almost impossible to use. For example, a common pattern is to create an object, then acquire the lock on a collection and add the object to the collection. This wouldn't work if acquiring the lock on the collection didn't guarantee that the writes involved in the creation of the object were visible.

在get()中,如果ready = true,则数据必须为o?我的意思是保证该线程可以看到数据的可见性?我认为数据不是易失性的,也不是get()同步的.这个线程可能会在缓存中看到旧值吗?

in get(), if ready = true, data must be o? I mean this thread is guaranteed to see the visibility of data? I think data is not a volatile nor the get() synchronized. Is this thread may see the old value in the cache?

定义

Java的volatile操作是为了确保看到一个更改的线程可以看到所有其他内存更改,并且该更改在该线程看到该更改之前,也对该线程进行了更改.在其他语言(例如C或C ++)中则不是这样.这可能会使Java的volatile在某些平台上更昂贵,但幸运的是,在典型的平台上不会如此.

Java's volatile operation is defined such that a thread that sees a change to one is guaranteed to see all other memory changes the thread that made that change made before it made the change the thread saw. This is not true in other languages (such as C or C++). This may make Java's volatiles more expensive on some platforms, but fortunately not on typical platforms.

另外,请不要谈论在缓存中".这与缓存无关.这是一个普遍的误解.它与可见性有关,而不是缓存.大多数缓存都可以提供对缓存的完全可见性(将"MESI协议"打入您喜欢的搜索引擎以了解更多信息),并且不需要任何特殊操作即可确保可见性.

Also, please don't talk about "in the cache". This has nothing to do with caches. This is a common misunderstanding. It has to do with visibility, not caching. Most caches provide full visibility into the cache (punch "MESI protocol" into your favorite search engine to learn more) and don't require anything special to ensure visibility.

这篇关于Java:易失性如何保证“数据"可见性?在这段代码中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆