有人能告诉我同步方法比同步块的优势与一个例子吗?


当前回答

In general these are mostly the same other than being explicit about the object's monitor that's being used vs the implicit this object. One downside of synchronized methods that I think is sometimes overlooked is that in using the "this" reference to synchronize on you are leaving open the possibility of external objects locking on the same object. That can be a very subtle bug if you run into it. Synchronizing on an internal explicit Object or other existing field can avoid this issue, completely encapsulating the synchronization.

其他回答

主要的区别是,如果你使用同步块,你可以锁定一个对象,而不是这个,这允许更灵活。

假设您有一个消息队列和多个消息生产者和消费者。我们不希望生产者相互干扰,但是消费者应该能够检索消息,而不必等待生产者。 我们只需要创建一个对象

Object writeLock = new Object();

从现在开始,每当制作人想要添加一条新信息时,我们就会锁定它:

synchronized(writeLock){
  // do something
}

因此,消费者可能仍会阅读,而生产者将被锁定。

As already said here synchronized block can use user-defined variable as lock object, when synchronized function uses only "this". And of course you can manipulate with areas of your function which should be synchronized. But everyone says that no difference between synchronized function and block which covers whole function using "this" as lock object. That is not true, difference is in byte code which will be generated in both situations. In case of synchronized block usage should be allocated local variable which holds reference to "this". And as result we will have a little bit larger size for function (not relevant if you have only few number of functions).

你可以在这里找到更详细的解释: http://www.artima.com/insidejvm/ed2/threadsynchP.html

在实际应用中,同步方法相对于同步块的优势在于它们更能抵抗白痴;因为您不能选择任意对象来锁定,所以您不能滥用synchronized方法语法来做一些愚蠢的事情,比如锁定字符串文字或锁定从线程下面更改的可变字段的内容。

另一方面,使用同步方法,您无法保护锁不被任何可以获得对象引用的线程获取。

因此,在方法上使用synchronized作为修饰符可以更好地保护你的奶牛免受伤害,而将synchronized块与私有final锁对象结合使用则可以更好地保护你自己的代码免受奶牛的伤害。

Synchronized方法用于锁定所有对象 同步块用于锁定特定对象

唯一的区别是:同步块允许颗粒状锁定,不像同步方法

基本上同步块或方法被用来编写线程安全的代码,以避免内存不一致的错误。

这个问题很老了,在过去的7年里,很多事情都发生了变化。 为了线程安全,引入了新的编程结构。

您可以通过使用高级并发API而不是同步块来实现线程安全。该文档页提供了实现线程安全的良好编程结构。

锁对象支持简化许多并发应用程序的锁定习惯用法。

executor为启动和管理线程定义了高级API。concurrent提供的执行器实现提供了适合大型应用程序的线程池管理。

并发集合使管理大型数据集合变得更容易,并且可以大大减少同步的需要。

原子变量具有最小化同步和帮助避免内存一致性错误的特性。

ThreadLocalRandom(在JDK 7中)提供了从多个线程有效生成伪随机数的功能。

更好的synchronized替代品是ReentrantLock,它使用Lock API

一个可重入互斥锁,其基本行为和语义与使用同步方法和语句访问的隐式监视锁相同,但具有扩展功能。

锁的例子:

class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() {
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }

其他编程结构也可以参考java.util.concurrent和java.util.concurrent.atomic包。

参考这个相关的问题:

同步vs锁定