【问题标题】:What are class level, object level, explicit and intrinsic locking?什么是类级别、对象级别、显式和内在锁定?
【发布时间】:2014-12-27 19:34:11
【问题描述】:

我一直在研究 Java 多线程概念。我越是经历它们,我就越感到困惑。

现在我不了解 Java 中类级别、对象级别、显式锁定和内在锁定之间的区别。有人可以告诉我这是什么吗?另外,如果我能得到一些例子来理解,那对我很有帮助。

【问题讨论】:

  • 你在哪里浏览它们?有什么具体的书吗?
  • @BartlomiejLewandowski :不,我正在查看各种互联网资源,他们把我搞糊涂了。
  • 我重新打开了这个。出于某种原因,它作为@AmanArora 链接到的问题的副本被关闭。然而,这两个问题完全不同。是的,链接到的答案提供了这个问题的一些答案,但这并不意味着它是一个骗子。

标签: java multithreading locking


【解决方案1】:

显式与内在

当您在对象上使用synchronized 或间接作为方法签名的一部分时,您正在创建intrinsic lock。您依赖与所有对象和类关联的内置锁。

在 Java 5+ 中的包 java.util.concurrent.locks 中提供了显式锁。最常用的类大概是ReentrantLock。这些提供了使用内在锁的替代方案,并提供了内在锁无法实现的功能。

类级别与对象级别

这种区别仅适用于内在锁。如果您有synchronized static method,则使用的内在锁将与类对象本身相关联。如果您在对象实例上进行同步(或具有同步的实例方法),它将是对象级锁。


进一步阅读

Brian Goetz 的 Java Concurrency in Practice 是一本出色的书,可帮助您了解 Java 多线程编程的噩梦般混乱的世界。

【讨论】:

  • 那么,也就是说,类级别和对象级别的锁实际上只是内在锁的子类型,但是显式锁/重入锁是完全不同的东西?
  • @TheDarkKnight 是的。但只是为了增加混乱,内在锁也是可重入的(即持有锁的人可以再次获取它)。
  • Ohhh....你杀了我 :) 好吧,这清除了大部分的东西。能否请您指出显式锁的任何代码片段?
  • 感谢您的信息。这让我很头疼。
  • @TheDarkKnight 在ReentrantLock 类Javadocs 中有一些简单的代码示例。否则我肯定 Google 是你的朋友。
【解决方案2】:

当您使用“Synchronized”关键字时,它会使用内部锁或监视器。 Java 中的每个对象都有一个与之关联的内在锁。每当线程尝试访问同步块或方法时,它都会获取内在锁或该对象上的监视器或对象级锁。在静态方法的情况下,线程获取对类对象的锁定

public synchronized void doAtomicTransfer(){
  //enter synchronized block , acquire lock over this object.
  operation1()
  operation2();   
} // exiting synchronized block, release lock over this object.

内在锁定机制可能有一些功能限制,例如:

  • 无法中断等待获取锁的线程(可中断锁)。
  • 如果不希望永远等待它,就不可能尝试获取锁(尝试锁)。一次只能有一个线程持有锁:没有任何便利,例如,允许多个线程同时持有一个锁以进行只读访问。
  • 无法实现非块结构的锁定规则,因为内部锁必须在获取它们的同一块中释放。

Explicit locks 在您需要克服内置同步的一些缺点的情况下很有用。特别是,它们具有以下特点:

  • 线程可以尝试以中断方式获取锁;
  • 线程可以为尝试获取锁提供超时值;
  • 支持读/写锁——也就是说,如果锁没有锁定写入,则允许多个并发读取的锁;
  • 传统的等待/通知比喻被扩展为允许条件(见下文);
  • 支持公平性(如果有多个线程在等待锁,它们会在可用时以先进先出的顺序获取);
  • 锁定超出块范围的能力:例如,一种方法可以将锁定对象传递给另一个线程;
  • 可以查询锁以查明,例如,它们当前是否有任何线程等待获取它们。

【讨论】:

  • 谢谢,这很有见地。
【解决方案3】:

“类级”锁定和“对象级”锁定是人为的想法,由可能对 Java 内在锁定的工作原理没有深入了解的作者创建。

类级锁定如下所示:

class Foobar {
    static synchronized void moo() { ... }
}

但这种结构实际上只是一种简写方式:

class Foobar {
    static void moo() {
        synchronized (Foobar.class) { ... }
    }
}

还有对象级锁定,看起来像这样:

class Foobar {
    synchronized void baa() { ... }
}

只是以下的简写:

class Foobar {
    static void baa() {
        synchronized (this) { ... }
    }
}

实际上,在“类级”和“对象级”锁定之下,只有一个概念,synchronized 块:

synchronized(objectReference) {...}

您只需要知道 JVM 不会允许多个线程同时在同一个对象上同步。

当您要保护的数据是全局数据时,在访问数据时在全局单例对象上进行同步是有意义的。 Foobar.class 是一个全局单例。

如果您要保护的数据完全包含在某个对象实例中,那么在与该实例关联的内容或实例本身(即this)上同步是有意义的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-24
    • 1970-01-01
    • 1970-01-01
    • 2011-11-10
    • 1970-01-01
    • 2021-12-27
    • 2012-04-27
    相关资源
    最近更新 更多