Java同步方法 - 它是如何工作的

8
我想我知道这个问题的答案,但还是希望确认一下。
显然,同步块会阻止其他线程访问该代码块,但我看到很多示例都是这样的。
   public synchronized void setValue(int value)
   {
       balance=value;
   }

我想,如果方法只有像上面那样的一行代码,那么就没有必要将它同步。

谢谢。


1
如果您只是获取或设置“balance”,则可以将其设置为“volatile”,但无法同时进行原子性的获取和设置。 - Peter Lawrey
4个回答

17

如果该方法只有像上面那样的一行代码,那么使用同步没有意义,这种想法正确吗?

不对。您似乎认为同步只提供原子性。

但它实际上提供了更多 - 特别是,它保证:

  • 原子性,对于一个只有一行分配语句的方法来说并不有用(除非在下面的边界情况中)
  • 可见性
  • 防止重排序
  • 互斥:在相同监视器上同步的两个方法不能同时运行

在您的示例中,如果没有同步,则无法保证当一个线程调用您的方法并且另一个线程随后读取balance时,第二个线程将看到更新后的值。

请注意,可见性必须在两端得到确保:写入和读取都需要使用相同的监视器进行同步。因此,getter getBalance 也需要被同步。

边界情况double和long的赋值操作不能保证是原子性的。因此,即使在像下面这样的一个一行示例中没有同步关键字,仍然有可能出现一个线程更新double的前32位,另一个线程更新后32位,从而创建一个混乱的balance变量。

public synchronized void setValue(double value) {
    balance = value;
}

“reading” 方法也必须同步才能实现这一点。 - fge

2
它不仅会阻止其他线程访问此方法:它还会阻止其他线程访问任何使用相同锁(在这里是实例)的块或方法。
重点是,如果另一个同步方法更长,则可以确保此方法不会同时运行。
如果其他方法依赖于“balance”变量在执行期间不发生变化,则这一点很重要。

好的,我明白了。所以它会锁定类中同步的所有方法。 - Matthew Smith
@MatthewSmith 不完全准确:它锁定了调用此方法的对象的实例。但由于锁是协作的,访问该值的其他方法也必须同步。 - fge

2

同步方法有两个作用:

  • 不允许多于1个线程执行该方法
  • 将线程内存缓存与共享内存同步。

在您的情况下,只有一个线程能够更新该变量,并且所有其他线程也会看到变量 balance 的最新数据。

如果没有同步,其他线程会使用其缓存的 balance 值(这是非常可能的),因此程序执行后会得到不一致的 balance 值。

您可以在此演示文稿中找到对您问题的非常好的解释。


0

多个线程可能会调用setValue方法并传入不同的值。因此,如果您真的想确保一个线程的更改对另一个线程可见,则该方法应该是同步的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接