假设我有一个与字段data共享的对象。多个线程将共享对此对象的引用,以便访问该字段。但是,线程从不并发地访问对象。是否需要将data声明为易失性的?
这种情况如下:
Counter定义了唯一的字段value和一个方法increment。考虑到程序本身的逻辑,无法并发访问计数器。然而,计数器是通过多个线程共享的。计数器必须是不稳定的吗?
这种情况的另一个变体是,多个线程通过依赖并发控制(wait、notify、synchronize)的另一个对象Y操作一个对象X,这个对象X是普通数据,但通过另一个依赖并发控制的对象Y交替执行它们的时间执行(这样X永远不会被并发访问)。对象X的字段应该是易失性的吗?
发布于 2013-10-14 06:51:21
只有在建立线程之间的关系之前,线程的突变才能在其他线程中可见。当建立起这种关系时,所有以前的突变都变得可见。
如果另一个对象正确地同步了对它的访问(请参见Java并发中的着色),隔离时未正确同步的对象可以安全地使用。
在问题中所述的两种情况下,我认为不需要同步:
Thread.start建立了一个发生之前的关系,因此以前线程中的所有突变都是可见的。如果您知道对象X从未被并发访问,那么很可能有一个对象Y间接地同步了对X的访问,所以它很好。我所看到的唯一不安全的情况是线程本身是否按时间中继(例如,使用Thread.sleep或循环直到某个时间中断)以保证互斥:在建立关系之前,在这种情况下不会发生。
发布于 2012-10-11 11:55:30
研究整个JLS关于Java内存模型的章节是非常推荐的--事实上,对于任何在Java中执行并发性的人来说都是强制性的。您的案例,特别是在JLS,17.4.4:中涵盖了。
“启动线程的动作与它启动的线程中的第一个动作同步。”
这意味着,对于第一个场景,您不需要volatile。但是,无论如何,让它对代码的未来更改保持健壮是很好的做法。您应该有一个很好的理由让(而不是)拥有volatile,只有在读取速率非常高(至少每秒数百万)的情况下才会有volatile。
发布于 2012-10-11 11:47:40
Java内存模型和字节码重新排序并不保证后续线程将看到计数器的增量值。因此,如果您使用单个线程--您不需要对挥发物做任何事情,但是如果有几个线程可能从变量中读取某些内容--您需要确保对另一个线程的更改的可见性,无论是易失性线程还是同步/锁线程。
Thread.start方法设置了屏障,因此可见性得到了保证--而且可能会发生这样的情况:您不需要那些易挥发的东西。但我还是会加进去的。
https://stackoverflow.com/questions/12838776
复制相似问题