Java中的同步方法和同步块有啥区别? [复制]

Posted

技术标签:

【中文标题】Java中的同步方法和同步块有啥区别? [复制]【英文标题】:What is the difference between a synchronized method and synchronized block in Java? [duplicate]Java中的同步方法和同步块有什么区别? [复制] 【发布时间】:2010-11-12 02:30:41 【问题描述】:

Java 中同步方法和同步块有什么区别?

我一直在网上寻找答案,人们似乎对这个不太确定:-(

我的看法是两者之间没有区别,只是同步块可能在范围内更加本地化,​​因此锁定的时间会更短??

如果在静态方法上使用 Lock,那么 Lock 是在什么情况下使用的? Lock on Class 是什么意思?

【问题讨论】:

@try-catch-finally 这不是这个问题的重复;该问题询问同步方法是仅提供对该方法的独占访问,还是对整个对象提供独占访问。 @MarkRotteveel 就不同的标题而言,您是对的。另一方面,另一个问题的答案也涵盖了差异:将同步部分的范围限定为(或不)某些语句并控制锁定位置(或无法控制)。 【参考方案1】:

同步方法使用方法接收器作为锁(即this 用于非静态方法,封闭类用于静态方法)。 Synchronized blocks 使用表达式作为锁。

所以下面两种方法从锁定角度来看是等价的:

synchronized void mymethod()  ... 

void mymethod() 
  synchronized (this)  ... 

对于静态方法,类会被锁定:

class MyClass 
  synchronized static mystatic()  ... 

  static mystaticeq() 
    syncrhonized (MyClass.class)  ... 
  

对于同步块,您可以使用任何非null 对象作为锁:

synchronized (mymap) 
  mymap.put(..., ...);

锁定范围

对于同步方法,锁将在整个方法范围内持有,而在synchronized 块中,锁仅在该块范围内(也称为临界区)持有。在实践中,如果 JVM 可以证明可以安全地完成,则允许通过从 synchronized 块执行中删除一些操作来进行优化。

【讨论】:

我前段时间读到(丢失了源代码),即使该块封装了整个方法体,JVM 内部的同步方法也比块上的同步更容易优化。可能是有趣的微基准测试。 在锁定范围内,您可能的意思是“......而在同步块中,锁定仅在同步块期间被持有”而不是“......而在同步方法中锁定是仅在同步块期间持有” @Gregory Mostizky 根据这篇文章,与同步块相比,JVM 为同步方法创建的字节码更少。 ibm.com/developerworks/java/library/j-5things15/…【参考方案2】:

同步方法是简写。这个:

class Something 
    public synchronized void doSomething() 
        ...
    

    public static synchronized void doSomethingStatic() 
        ...
    

就所有意图和目的而言,等同于:

class Something 
    public void doSomething() 
        synchronized(this) 
            ...
        
    

    public static void doSomethingStatic() 
        synchronized(Something.class) 
            ...
        
    

(其中Something.class 是类Something 的类对象。)

确实,使用同步块,您可以更具体地了解您的锁,并且更细粒度地了解您想要使用它的时间,但除此之外没有任何区别。

【讨论】:

【参考方案3】:

是的,这是一个区别。另一个是你可以获取除this之外的其他对象的锁。

【讨论】:

【参考方案4】:

关键的区别在于:如果你声明一个方法是同步的,那么整个方法体就会同步;但是,如果您使用同步块,那么您可以只将方法的“关键部分”包含在同步块中,而将方法的其余部分留在块之外。

如果整个方法是关键部分的一部分,那么实际上没有区别。如果不是这种情况,那么您应该仅在关键部分周围使用同步块。同步块中的语句越多,获得的整体并行度就越低,因此您希望将这些语句保持在最低限度。

【讨论】:

快速跟进:这是否意味着同步块的使用成本低于同步方法? 如果同步块包含函数的所有内容,那么没有区别。但是,如果您使用同步块,则可以只围绕关键部分(也许将一些计算留在同步区域之外)。如果你这样做,你的程序会运行得更快。【参考方案5】:

同步方法锁定该方法所在的对象实例。

同步块可以锁定任何对象——通常是定义为实例变量的互斥对象。这样可以更好地控制正在运行的锁。

【讨论】:

【参考方案6】:

我的看法是两者之间没有区别,只是同步块可能在范围内更加本地化,​​因此锁定的时间会更短??

是的。你说的对。与synchronized 方法不同,同步语句必须指定提供内在锁的对象。

java教程中的例子:

public void addName(String name) 
    synchronized(this) 
        lastName = name;
        nameCount++;
    
    nameList.add(name);

同步语句对于通过细粒度同步提高并发性也很有用。您可以在以下用例的同一教程页面上找到很好的示例。

例如,假设类MsLunch 有两个实例字段c1 和c2,它们从不一起使用。这些字段的所有更新都必须是synchronized,但是没有理由阻止 c1 的更新与 c2 的更新交错 - 这样做会通过创建不必要的阻塞来降低并发性。 我们不使用同步方法或以其他方式使用与此关联的锁,而是创建两个对象来提供锁

如果在静态方法上使用 Lock,那么 Lock 是在什么情况下使用的? Lock on Class 是什么意思?

在这种情况下,线程获取与类关联的 Class 对象的内在锁。因此,对类的静态字段的访问由一个锁控制,该锁不同于该类的任何实例的锁。

当您将方法设为synchronized(非static)时:

在同一对象上两次调用synchronized 方法是不可能交错的。当一个线程正在为一个对象执行同步方法时,所有其他为同一对象调用同步方法的线程都会阻塞(暂停执行),直到第一个线程处理完该对象。

如果您将方法设为static synchronized

在同一类的不同对象上两次调用static synchronized 方法是不可能交错的。当一个线程正在为 A 类对象执行 static synchronized 方法时,所有其他在 A 类对象上调用 static synchronized 方法的线程都会阻塞(暂停执行),直到第一个线程完成该方法执行。

您可以在这个 SE 问题中找到更好的同步替代方案:

Avoid synchronized(this) in Java?

【讨论】:

以上是关于Java中的同步方法和同步块有啥区别? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

java中HashMap和HashTable有啥共同点和区别

RSpec:let 和 before 块有啥区别?

java构造代码块和构造函数内的代码块有啥区别,谁先执行

java中同步和异步有啥异同?

操作系统中的页面和块有啥区别?

方法同步与对象同步有啥不同? [复制]