有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java空同步(this){}对线程之间的内存可见性有任何意义吗?

我在对StackOverflow的一篇投赞成票的评论中读到:

But if you want to be safe, you can add simple synchronized(this) {} at the end of you @PostConstruct [method]

[注意变量不是易变的]

我认为只有当写入和读取都在synchronized块中执行或者至少读取是易变的时,才会在强制执行之前发生

引用的句子正确吗?空的synchronized(this) {}块是否将当前方法中更改的所有变量刷新为“通用可见”内存

<强>请考虑一些SnEnvior <强>

  • 如果第二个线程从不调用this上的锁怎么办?(假设第二个线程读取其他方法)。记住这个问题是关于:刷新对其他线程的更改,而不是给其他线程一种方式(同步)轮询原始线程所做的更改。正如最初的评论所说,在Spring @PostConstruct上下文中很可能没有其他方法中的同步

  • 更改的内存可见性是否仅在另一个线程的第二次和后续调用中强制执行?(请记住,此同步块是我们方法中的最后一个调用))-这会将这种同步方式标记为非常糟糕的做法(第一次调用中的值过时)


共 (2) 个答案

  1. # 1 楼答案

    monitor exit之前发生的所有写操作对monitor enter之后的所有线程都可见

    一个synchronized(this){}可以像

    monitorenter
    monitorexit
    

    因此,如果在synchronized(this){}之前有一堆写操作,它们可能会在monitorexit之前发生

    这就引出了我第一句话的下一点

    visible to all threads after a monitor enter

    所以现在,为了让线程确保发生写入,它必须执行相同的同步,即synchornized(this){}。这将至少发出一个monitorenter,并在订购前确定您的位置


    所以来回答你的问题

    Does an empty synchronized(this) {} block flush all variables changed in current method to "general visible" memory?

    是的,只要在读取这些非易失性变量时保持相同的同步

    来回答你的其他问题

    what if second thread never calls lock on this? (suppose that second thread reads in other methods). Remember that question is about: flush changes to other threads, not give other threads a way (synchronized) to poll changes made by original thread. Also no-synchronization in other methods is very likely in Spring @PostConstruct context

    在这种情况下,在没有任何其他上下文的情况下使用synchronized(this)是相对无用的。恋爱之前没有发生过什么,从理论上讲,它和不包含它一样有用

    is memory visibility of changes forced only in second and subsequent calls by another thread? (remember that this synchronized block is a last call in our method) - this would mark this way of synchronization as very bad practice (stale values in first call)

    内存可见性由第一个调用synchronized(this)的线程强制执行,因为它将直接写入内存。现在,这并不一定意味着每个线程都需要直接从内存中读取。他们仍然可以从自己的处理器缓存中读取数据。使用线程调用synchronized(this)可以确保它从内存中提取字段的值,并检索最新的值

  2. # 2 楼答案

    遗憾的是,关于这篇文章的许多内容,包括这篇文章中的许多答案/评论,都是错误的

    这里应用的Java内存模型中的关键规则是:给定监视器上的解锁操作发生在同一监视器上的后续锁定操作之前。如果只有一个线程获得了锁,那么它就没有意义了。如果虚拟机可以证明锁对象是线程受限的,那么它就可以避开它可能发出的任何围栏

    您突出显示的引用假定释放锁起到完全隔离的作用。有时候这可能是真的,但你不能指望。所以你的怀疑是有根据的

    有关Java内存模型的更多信息,请参见第16章Java Concurrency in Practice