synchronized(this)和synchronized(ClassName.class)的区别是什么?

17

我在某个地方读到过,应该避免使用synchronized(this),出于各种原因。然而,我遇到的一些值得尊敬的代码在构造函数中使用了以下内容:

public SomeClass(Context context) {
  if (double_checked_lock == null) {
    synchronized (SomeClass.class) {
      if (double_checked_lock == null) {
        // some code here
      }
    }
  }
}

synchronized(this)synchronized(SomeClass.class)之间真的有区别吗?

6个回答

35

synchronized(this) 是在当前对象上同步,因此每个实例只能被一个线程访问,但不同的线程可以访问不同的实例。例如,您可以为每个线程创建一个实例。

这通常是为了防止多个线程同时更新一个对象,这可能会导致不一致的状态。

synchronized(SomeClass.class) 是在当前对象(或另一个类,如果需要)的上同步,因此一次只能有一个线程访问该类的任何实例。

这可能用于保护跨类所有实例共享的数据(例如实例缓存或总实例数的计数器)不会进入不一致的状态。


2
+1。这更清晰地区分了类锁和对象锁。我没有找到比这更好的东西。简短易懂 - Ravi

7

this 是每个实例都不同的。
ClassName.class 则是相同的。

因此,synchronized(this) 可以允许多个实例同时运行。


3
synchronized 关键字在应用于 class 时对类进行锁定,在应用于 this 时对当前对象实例进行锁定。Java 语言规范第 8.4.3.6 节“同步方法”中有详细描述:
“在执行 synchronized 方法之前,它会获取一个监视器(§17.1)。对于类(静态)方法,使用与该方法所在类的 Class 对象相关联的监视器,而对于实例方法,则使用与 this 相关联的监视器(调用该方法的对象)。 ”

3
每个Java对象都可以有一个锁。这个锁最多只能由一个线程持有,任何其他线程必须等待获取相同对象的锁。
- synchronized(this) 为当前线程获取实例 this 的锁。该方法可以在不同实例上并行运行(具有不同的this值和因此不同的锁)。 - synchronized(SomeClass.class) 获取 SomeClass 的全局类对象的锁。只有一个方法的实例可以运行,因为所有对象实例都在同一个全局对象上加锁(相同的锁)。

1

synchronized(this)会在对象实例上同步。

synchronized(SomeClass.class)使用代表SomeClass的Class对象实例,该实例对于同一类加载器中的所有实例都是全局的。

因此,这些是具有不同语义的不同结构。

仅使用synchronized或作为方法修饰符时,还会在实例的信号量上同步,该信号量通常用于防止多个线程访问该实例作为共享资源(例如List)而发生争用。

您所提到的线程指出,直接在对象实例上同步可能是危险的,因此最好使用私有实例。 为此,您可以使用:

class MySharedResourceClass {

    private SomeClass lock = new SomeClass();

    public doSomething() {
        synchronized (lock) {
            // Do something here
        }
    }
}

1
这是两个不同的对象可以锁定: 'this' 指当前实例上下文,因此如果每个线程使用不同的实例并锁定它,则创建多个实例将没有效果。 'this' 只能在非静态上下文中引用。
'class' 是 Java 类的静态成员,只有一个实例。您可以在静态和非静态上下文中都锁定它。

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