.class 的 Java 同步块

Posted

技术标签:

【中文标题】.class 的 Java 同步块【英文标题】:Java Synchronized Block for .class 【发布时间】:2011-01-04 14:27:27 【问题描述】:

这段java代码是什么意思?它会锁定MyClass的所有对象吗?

synchronized(MyClass.class) 
   //is all objects of MyClass are thread-safe now ??

上面的代码和这个有什么不同:

synchronized(this) 
   //is all objects of MyClass are thread-safe now ??

【问题讨论】:

相关:***.com/questions/437620/… 【参考方案1】:

sn-p synchronized(X.class) 使用类实例作为监视器。由于只有一个类实例(在运行时表示类元数据的对象),因此该块中可以有一个线程。

synchronized(this) 块由实例保护。对于每个实例,只有一个线程可以进入块。

synchronized(X.class) 用于确保块中只有一个线程。 synchronized(this) 确保每个实例只有一个线程。如果这使得块中的实际代码线程安全取决于实现。如果只改变实例synchronized(this)的状态就足够了。

【讨论】:

“有多少实例就有多少线程可以进入块”意味着第二种形式充当信号量,这是不正确的。你应该这样说:“同步(this)确保只有一个线程可以进入给定类实例的块”。 已更正。我是想这么说的。 类实例与实例是什么? 所以,如果你有一个静态方法并且我们不想同步它的所有主体,那么我们 synchronized(this) 不好,而是 synchronized(Foo.class) 是合适的。对吗? synchronized(X.class) is used to make sure that there is exactly one Thread in the block. 这是错误的,这取决于你有多少类加载器【参考方案2】:

添加到其他答案:

static void myMethod() 
  synchronized(MyClass.class) 
    //code
  

等价于

static synchronized void myMethod() 
  //code

void myMethod() 
  synchronized(this) 
    //code
  

等价于

synchronized void myMethod() 
  //code

【讨论】:

我读了第二遍才发现前两个例子有关键字“static”。只是向可能已经看到并错过它的其他人指出这一点。如果没有 static 关键字,前两个示例将不一样。 这些例子并不等同!当线程尝试调用方法时,同步方法被“同步”为一个漏洞。另一方面,这些块可以在它们上面和下面有代码,可以从多个线程中执行。它们只在块内同步!那不一样! public static Singleton getInstance() if (instance == null) synchronized (Singleton.class) instance = new Singleton(); 返回实例; 重点是在synchronized 块之外没有代码。这使它们等效。如果你换一个例子,它们确实不再一样了。 只需添加 synchronized(MyClass.class) 也可以从其他类中使用,而不仅仅是在 MyClass 中使用。我有一个遗留代码,其中几个类使用一个类的方法(比如说 Foo.saveStuff)。我需要确保一次只有一个线程使用 saveStuff。由于糟糕的数据库事务设计,我不能只使 safeStuff 同步,所以我必须在所有其他方法中使用 synchronized(Foo.class)。【参考方案3】:

不,第一个将锁定MyClass 的类定义,而不是它的所有实例。但是,如果在一个实例中使用,这将有效地阻止所有其他实例,因为它们共享一个类定义。

第二个将只锁定当前实例。

至于这是否使您的对象线程安全,这是一个复杂得多的问题 - 我们需要查看您的代码!

【讨论】:

是的,MyClass.class 可以是任何静态变量并且具有相同的效果。【参考方案4】:

是的,它会(在任何同步块/功能上)。

我为自己想了几天这个问题(实际上是在 kotlin 中)。终于找到了很好的解释,想分享一下:

类级锁可防止多个线程在运行时进入类的所有可用实例中的同步块。这意味着如果在运行时有 100 个 DemoClass 实例,那么一次只有一个线程能够在任何一个实例中执行 demoMethod(),而所有其他实例都将被其他线程锁定。

应始终进行类级锁定以确保静态数据线程安全。我们知道 static 关键字将方法的数据与类级别相关联,因此在静态字段或方法上使用锁定使其在类级别。

还要注意为什么 .class。只是因为.class 等价于类的任何静态变量,类似于:

private final static Object lock = new Object();

其中锁变量名称为class,类型为Class

阅读更多: https://howtodoinjava.com/java/multi-threading/object-vs-class-level-locking/

【讨论】:

这不是真的,是的,它会阻止来自同一个类加载器的所有实例!

以上是关于.class 的 Java 同步块的主要内容,如果未能解决你的问题,请参考以下文章

深入理解Java中的同步静态方法和synchronized(class)代码块的类锁

JAVA SE基础篇59.同步块并发容器和死锁

多线程基础

2.2.9静态同步synchronized方法与synchronized(class)代码块

区分同步代码块静态同步方法非静态同步方法的锁

java多线程-同步块