同步方法中的同步块 [英] Synchronized Block within Synchronized Method

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

问题描述

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

I'm looking at some code in a third party library that contains a synchronized method, and within this method there is a synchronized block that locks on an instance variable. It's similar to this:

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

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

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

Does this make sense? If so, what benefits are there to having a synchronized statement within a synchronized method?

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

Given that a synchronized method locks on the entire object, it seems redundant to me. Perhaps this approach makes sense when working with instance variables that are not private?

推荐答案

在您的示例中,方法是 锁定 Foo 的实例以及对象 bar 。其他方法可能只锁定对象上的 Foo 的实例。

In your example the method is both locking on the instance of Foo and on the object bar. Other methods may only be locking on the instance of Foo or on the object bar.

所以,是的,这取决于他们究竟在做什么。据推测 bar 保护一些较小的数据子集,有些方法只需锁定 bar 即可执行其中的操作一种线程安全的方式。

So, yes, this makes sense depending on exactly what they are doing. Presumably bar protects some smaller subset of data, and some methods will only need to lock on bar to perform their actions in a thread-safe manner.

synchronized (在方法上或在语句中)创建一个互斥区域( 关键部分 或者,特别是对于Java, reentrant mutex )。线程进入临界区的键是 synchronized 语句中使用的对象引用。只有一个线程可以(递归地)在使用相同密钥的所有块上拥有该密钥;也就是说,一次只有一个线程可以在给定的对象引用上输入任何块 synchronized

synchronized (on a method, or in a statement) creates a mutual exclusion zone (critical section or, specifically for Java, a reentrant mutex). The "key" for a thread to enter the critical section is the object reference used in the synchronized statement . Only one thread can (recursively) "own" this "key" at one time across all blocks that use the same key; that is, only one thread can enter any block synchronized on a given object reference at one time.

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

Such a critical section simply prevents the operations (variable read/write) that you do inside the block happening concurrently with any other operations in all other critical sections that lock on the same object reference. (It doesn't automatically protect all variables inside an object).

在Java中,这样一个关键部分也会创建一个 发生在 合同之前。

In Java, such a critical section also creates a happens-before contract.

作为一个有点人为的例子

As a somewhat contrived example :

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

}

是否实例变量是私有的还是不是这种方法是否适用并不重要。在单个类中,您可以拥有多个锁定对象,每个锁定对象都保护自己的数据集。

Whether the instance variables are private or not doesn't really matter to whether this approach is applicable. In a single class you can have multiple lock objects, each of which protect their own set of data.

然而,执行此操作的风险是您必须非常严格的编码约定,通过在不同的地方锁定不同顺序的两个锁来防止死锁。例如,如果您从代码中的其他位置执行此操作,请使用上面的代码:

However the risk of doing this is that you have to be very strict with coding conventions to prevent deadlocks by locking two locks in different orders in different places. For example, with the above code if you then do this from somewhere else in the code:

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

使用 incrementBarCounterIfAllowed()<可能导致死锁/ code>方法

you risk a deadlock with the incrementBarCounterIfAllowed() method

请注意 barCounter 可以是 Bar 等的实例变量等 - 为了简洁起见,我避免使用它。

Note that barCounter could be an instance variable for Bar etc etc - I avoided that for the sake of brevity in the code sample.

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

In the case of synchronized methods, that reference is the reference to the class instance (or to the Class<?> for the class for static methods).

这篇关于同步方法中的同步块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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