字段读取同步和 volatile 的区别 [英] Difference between synchronization of field reads and volatile

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

问题描述

在一篇不错的文章中并发提示,一个例子被优化为以下几行:

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 的值是当前的,并且任何对 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.

这个例子让我想到了一点:将acct.balance(即类Account的字段余额)声明为volatile不是更有效吗?它应该更有效,保存您访问 acct.balance 的所有 synchronize 并且不会锁定整个 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 提供了可见性保证.synchronized 提供了可见性保证和受保护代码段的序列化.对于非常简单的情况,使用 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.

如果您假设 Account 有调整余额的方法,那么 volatile 还不够好

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;
}

如果余额不稳定且没有其他同步,我们就会遇到问题.如果两个线程尝试一起调用 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 而不是同步的",答案很可能是是",但确定它的时间/努力以及弄错的危险是不值得的好处(次要性能).

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.

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

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