字段读取的同步和易失性之间的差异 [英] Difference between synchronization of field reads and volatile

查看:134
本文介绍了字段读取的同步和易失性之间的差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在一个很好的文章一些并发提示,一个示例优化了以下行:

In a nice article with some concurrency tips, an example was optimized to the following lines:

double getBalance() {
    Account acct = verify(name, password);
    synchronized(acct) { return acct.balance; }
}



如果我正确理解,同步的要点是确保由该线程读取的acct.balance的值是current,并且对acct.balance中的对象的字段的任何未决写入也被写入主存储器。

If I understand that correctly, the point of the synchronization is to ensure that the value of acct.balance that are read by this thread is current and that any pending writes to the fields of the object in acct.balance are also written to main memory.

这个例子让我想起了一点:只是声明a​​cct.balance(即Account类的字段平衡)为 volatile ?它应该更高效,保存对访问acct.balance的所有同步,并且不会锁定整个 acct 目的。我错过了什么?

The example made me think a little: wouldn't it be more efficient to just declare acct.balance (i.e. the field balance of class Account) as volatile? It should be more efficient, save you all the synchronize on accesses to acct.balance and would not lock the whole acct object. Am I missing something?

推荐答案

你是正确的。 volatile提供了可见性保证。同步提供了受保护代码段的可见性保证和序列化。对于非常简单的情况,volatile是足够的,但是很容易陷入麻烦,使用volatile而不是同步。

You are correct. volatile provides a visibility guarantee. synchronized provides both a visibility guarantee AND serialisation of protected code sections. For VERY simple situations volatile is enough, however it is easy to get into trouble using volatile instead of synchronisation.

如果你假设帐户有一种方法来调整余额不够好

If you were to assume that Account has a way of adjusting its balance then volatile is not good enough

public void add(double amount)
{
   balance = balance + amount;
}

然后我们有一个问题,如果balance是volatile,没有其他同步。如果两个线程尝试调用add()在一起,你可能有一个错过更新发生以下情况

Then we have a problem if balance is volatile with no other synchronization. If two threads were to try and call add() together you could have a "missed" update where the following happens

Thread1 - Calls add(100)
Thread2 - Calls add(200)
Thread1 - Read balance (0)
Thread2 - Read balance (0)
Thread1 - Compute new balance (0+100=100)
Thread2 - Compute new balance (0+200=200)
Thread1 - Write balance = 100
Thread2 - Write balance = 200 (WRONG!)

显然这是错误的,因为两个线程都读取当前值并独立更新,然后写回(读,计算,写)。 volatile在这里没有帮助,所以你需要同步,以确保一个线程在另一个线程开始之前完成整个更新。

Obviously this is wrong because both threads read the current value and updated independently and then wrote it back (read, compute, write). volatile does not help here so you would need synchronized to ensure one thread completed the entire update before the other thread began.

我一般发现,如果当写一些代码我可以使用volatile而不是synchronized,答案可能是是,但是确定的时间/努力的确定和错误的危险是不值得的利益(次要性能)。

I general find that if when writing some code I think "can I use volatile instead of synchronized" the answer might well be "yes" but the time/effort of figuring it out for sure and the danger of getting it wrong is not worth the benefit (minor performance).

由于一个写得很好的Account类会在内部处理所有的同步逻辑,所以呼叫者不用担心。

As an aside a well written Account class would handle all the synch logic internally so callers don't have to worry about it.

这篇关于字段读取的同步和易失性之间的差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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