空的synced(this){}是否对线程之间的内存可见性有任何意义?
问题内容:
我在关于StackOverflow的评论中阅读了这篇文章:
但是,如果您想安全起见,可以在@PostConstruct的末尾添加简单的synced(this){} [方法]
[请注意变量不是可变的]
我在想,只有在块中执行写入和读取操作,或者至少读取是易失性操作 时,才会 强制执行 before-beforesynchronized
。
引用的句子正确吗?空synchronized(this) {}
块是否将当前方法中所有更改的变量刷新到“常规可见”内存中?
请考虑一些场景
-
如果第二个线程从不调用锁
this
怎么办?(假设第二个线程以其他方法读取)。请记住,这个问题是关于: 刷新对其他线程的更改 ,而不是 给其他线程一种方式(同步的)来轮询原始线程所做的更改 。同样,在Spring@PostConstruct
上下文中,其他方法中的不同步也很有可能-如原始评论所述。 -
更改的内存可见性是否仅在另一个线程的第二次和后续调用中才强制执行?(请记住,此同步块是我们方法中的 最后一次 调用)-这会将这种同步方式标记为非常不好的做法(首次调用中的值过时)
问题答案:
在a之前发生的所有写操作对a monitor exit
之后的所有线程可见monitor enter
。
一个synchronized(this){}
可以变成像字节码
monitorenter
monitorexit
因此,如果在写入之前有大量写入操作,则synchronized(this){}
这些写入操作将在之前发生monitorexit
。
这将我们带到我的第一句话的下一点。
对所有线程可见
monitor enter
因此,现在,为了使线程确保发生写操作,它必须执行相同的同步,即synchornized(this){}
。这将至少发出a
monitorenter
并确定您在订购之前发生的情况。
所以回答你的问题
空的synced(this){}块是否会将当前方法中更改的所有变量都刷新到“一般可见”的内存中?
是的,只要您想读取那些非易失性变量时保持相同的同步性即可。
解决您的其他问题
如果第二个线程从不调用锁怎么办?(假设第二个线程以其他方法读取)。请记住,这个问题是关于:刷新对其他线程的更改,而不是给其他线程一种方式(同步的)来轮询原始线程所做的更改。在Spring
@PostConstruct上下文中,其他方法中的不同步也很有可能
那么在这种情况下,synchronized(this)
没有任何其他上下文的使用是相对无用的。没有事前发生的关系,从理论上讲,它和不包括它一样有用。
更改的内存可见性是否仅在另一个线程的第二次和后续调用中才强制执行?(请记住,此同步块是我们方法中的最后一次调用)-这会将这种同步方式标记为非常不好的做法(首次调用中的值过时)
内存可见性是由第一个调用的线程强制执行的synchronized(this)
,因为它将直接写入内存。现在,这并不一定意味着每个线程都需要直接从内存中读取。他们仍然可以从自己的处理器缓存中读取。进行线程调用synchronized(this)
可确保它从内存中提取字段的值并检索最新的值。