【问题标题】:Synchronized data read/write to/from main memory同步数据读/写到/从主存储器
【发布时间】:2012-07-28 20:05:31
【问题描述】:

当一个同步方法完成时,是只把它修改过的数据推送到主存,还是把所有的成员变量都推送到主存,同理,一个同步方法执行时,是只从主存中读取它需要的数据,还是只从主存中读取?清除缓存中的所有成员变量并从主存中读取它们的值?例如

public class SharedData
{

    int a; int b; int c; int d;

    public SharedData()
    {
        a = b = c = d = 10;
    }

    public synchronized void compute()
    {
        a = b * 20;
        b = a + 10;
    }

    public synchronized int getResult()
    {
        return b*c;
    }

}

在上面的代码中,假设计算由线程A执行,getResult由线程B执行。在执行计算之后,线程A 将使用 a 和 b 更新主内存还是更新 a、b、c 和 d。在执行 getResult 之前,threadB 会从主内存中仅获取 b 和 c 的值,还是会清除缓存并获取所有成员变量 a、b、c 和 d 的值?

【问题讨论】:

    标签: java multithreading caching synchronization java-memory-model


    【解决方案1】:

    1. synchronized关键字在方法或原子语句上,将锁定访问 它可以修改的资源,只允许一个线程获得锁。

    2. 现在防止将值缓存到变量中由 volatile 关键字完成。 使用volatile关键字将要求JVM使访问实例变量的线程将其实例变量的副本与保存在内存中的副本相协调。

    3. 而且在你上面的例子中,如果threadA执行compute(),那么threadB 不能同时访问getResult()方法 ,因为它们都是同步方法,只有一个线程可以访问对象的所有同步方法,导致its not the method that is locked but the Object. Itslike this... Every object has one lock, and the thread which wants to access its synchronized block must get that lock

    4.甚至每个类都有一个锁,用来保护类中静态变量的关键状态。

    【讨论】:

    • 我的问题不是关于锁,我的问题是关于内存模型,在同步方法执行期间值如何从缓存中与主内存同步。
    • 在同步过程中没有同步机制......就像这样......当一个线程改变一个关键数据的状态时,一旦线程A完成,没有其他线程可以访问该数据with 并且锁被释放,那么另一个线程 B 可以对其进行读写,而此时线程 A 无法访问该状态的数据。使用 volatile 关键字时会完成缓存预防机制......这就是我试图在我的回答中解释的......
    • 谢谢。假设代码在多处理器环境中运行,线程 A 在处理器 1 中执行,线程 B 在处理器 2 中执行。假设两个线程都在处理器缓存中本地缓存 SharedData 实例(如上例)。在时间 t1,threadA 执行 compute() 方法并释放锁。经过一段时间 t1+delta(实例上没有锁定),threadB 执行 getResult() 方法。现在 threadB 需要在执行 getResult() 之前为 SharedData 实例的成员值刷新处理器缓存。哪些成员变量会被刷新(b&c 或 all)?
    【解决方案2】:

    我认为下面的帖子应该回答你的问题。

    Memory effects of synchronization in Java

    实际上,不会刷新整个缓存。

    【讨论】:

    • 感谢您浏览了您提供的链接。他们得出的结论是不会发生完全冲洗。但这是基于他们的假设,他们没有参考任何证据。他们是否有任何确认完全缓存刷新不会发生的 jvm 规范?
    • 抱歉回复晚了。 JVM 规范只是定义了一个契约。实现通常不提供细节。最后,刷新整个缓存的成本很高。因此,从逻辑上讲,实现会尽可能地进行优化。
    【解决方案3】:

    synchronized 确保您拥有一致的数据视图。这意味着您将读取最新值,而其他缓存将获得最新值。缓存足够智能,可以通过特殊总线相互通信(JLS 不需要,但允许这样做)这种总线意味着它不必接触主内存即可获得一致的视图。

    【讨论】:

    • 谢谢。那么为什么我们需要在 Java 中使用 volatile 关键字呢?请查看此链接link
    • 如果你只使用synchronized,你就不需要volatile。如果您有一个非常简单的操作,而同步操作会过大,那么 Volatile 很有用。
    • @PeterLawrey 先生,我对同步块有一些相关的疑问,如果您能就我的问题启发我,将非常有帮助:stackoverflow.com/q/42163468/504133
    • @nits.kk 你的问题的答案是;是的。如果没有同步写入,同步读取就没有任何意义。
    • @MohammadKarmi 只读一致,是的。如果您使用多个锁,则不能原子地进行读/写。也就是说,你得到的保证不比 volatile 多。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-23
    • 1970-01-01
    相关资源
    最近更新 更多