当前位置: 首页 > 面试题库 >

同步方法中的同步块

喻子航
2023-03-14
问题内容

我正在查看包含同步方法的第三方库中的一些代码,在此方法中,有一个锁定在实例变量上的同步块。与此类似:

public class Foo {
   final Bar bar = new Bar();

   public synchronized void doSomething() {
       // do something
       synchronized(bar) {
           // update bar
       }
   }
   ...
}

这有意义吗?如果是这样,在同步方法中使用同步语句有什么好处?

鉴于同步方法锁定了整个对象,对我来说似乎是多余的。在使用非私有的实例变量时,这种方法是否有意义?


问题答案:

在您的示例中,该方法 同时 锁定了Foo和的实例bar。其他方法可能仅锁定对象的实例Foo 对象bar

因此,是的,这完全取决于他们在做什么。大概bar可以保护一些较小的数据子集,并且某些方法只需要锁定就bar可以以线程安全的方式执行其操作。

是什么synchronized

synchronized(在方法上或在语句中)创建互斥区(
关键部分,
或者对于Java特别是
可重入互斥体

)。线程进入关键部分的“关键”是synchronized语句‡中使用的对象引用。在使用同一密钥的所有块中,一次只能有一个线程(递归)“拥有”该“密钥”;也就是说,一次只能有一个线程可以输入synchronized给定对象引用上的任何块。

这样的关键部分只是防止您在块内执行的 操作
(变量读/写)与锁定同一对象引用的所有其他关键部分中的任何其他操作同时发生。(它不会自动保护对象内的所有变量)。

在Java中,这样的关键部分还会
合同
之前 创建一个
偶然事件

举个例子

作为一个人为的例子†:

public class Foo {
    final Bar bar = new Bar();

    private int instanceCounter = 0;
    private int barCounter = 0;

    public synchronized void incrementBarCounterIfAllowed() {
        synchronized (bar) {
            if (instanceCounter < 10) barCounter++;
        }
    }

    public synchronized void incrementClassCounter() {
        instanceCounter++;
    }

    public void incrementBarCounter() {
        synchronized (bar) {
            barCounter++;
        }
    }

}

实例变量是否是私有的与这种方法是否适用无关紧要。在单个类中,您可以有多个锁对象,每个锁对象都保护自己的数据集。

但是这样做的风险是,你必须是 非常 严格的编码规范,以防止死锁通过在不同的地方不同的顺序锁两把锁。例如,使用上面的代码,然后从代码中的其他位置进行操作:

synchronized(myFoo.bar) {
  myFoo.incrementClassCounter();
}

您可能会为此incrementBarCounterIfAllowed()方法陷入僵局

请注意,这barCounter可能是Baretc等的实例变量-为了简洁起见,我避免了这样做。

‡对于synchronized方法,该引用是对类实例的引用(或Class<?>static方法的类的引用)。



 类似资料:
  • 请看下面给我带来麻烦的方法: 然后是run方法:

  • 问题内容: 在Java中制作异步方法的同步版本的最佳方法是什么? 假设您有一个使用以下两种方法的类: 您将如何实现直到任务完成才返回的同步? 问题答案: 看看CountDownLatch。您可以使用以下类似方式模拟所需的同步行为: 您还可以通过2个参与者使用相同的行为,如下所示: 但是,如果您可以控制I 的源代码,建议您重新设计它以返回一个对象。这样,您可以在需要时轻松地在异步/同步行为之间进行切

  • 同步调用异步方法最安全的方法是什么?

  • 问题内容: Java中的同步方法和同步块有什么区别? 我一直在网上搜索答案,人们似乎对此不太确定:-( 我的看法是,两者之间没有区别,只是synch块的作用域可能更多,因此锁定的时间更少了? 如果在静态方法上使用Lock,则采用什么Lock?班级锁是什么意思? 问题答案: 同步方法将方法接收器用作锁(即,用于非静态方法,而用于静态方法的封闭类)。 blocks将表达式用作锁。 因此,以下两种方法等

  • 为什么下面的代码不能保证多个线程之间total_home数字的唯一性,即使逻辑处于同步块中。 } } } 这是一个程序示例。试着运行5-10次,你会发现total_home的值并不是每次都是唯一的。

  • 问题内容: 我已经开始学习线程同步。 同步方法: 同步块: 什么时候应该使用方法和块? 为什么块比方法更好? 问题答案: 这不是更好的问题,只是有所不同。 同步方法时,实际上是在与对象本身进行同步。对于静态方法,您正在同步到对象的类。因此,以下两段代码以相同的方式执行: 就像您写的一样。 如果要控制到特定对象的同步,或者只想将方法的 一部分 同步到该对象,则指定一个块。如果在方法声明上使用关键字,