【问题标题】:Locks in Synchronized Blocks同步块中的锁
【发布时间】:2010-12-21 08:33:18
【问题描述】:

我只需要确认我已正确理解同步块中的锁的概念。 首先,我将讲述我所了解的。 获取对象的锁意味着没有其他线程可以访问对象类的同步代码。在同步方法的情况下,线程获取用于调用该方法的对象的锁(即隐含的 this 引用)。这意味着其他线程无法访问当前对象类的同步代码。但是,在同步块的情况下,我们可以指定我们希望线程获取锁的对象。

现在假设我们在 A 类的一个方法中的同步块获取了 B 类对象的锁。假设一个线程进入这个同步块并获取了 B 类特定对象的锁。

如果任何其他线程使用 B 类的相同对象,它将无法进入 A 类中的同步块,对吗? 而且其他线程也不能访问B类中的任何同步代码?

那么 A 类中的其他同步代码呢?因为线程已经获得了B类对象的锁,其他线程可以访问A类的其他同步代码吗?这意味着A类的对象没有锁,只有B类?

我希望人们能理解我的问题。

提前致谢。

【问题讨论】:

  • 就类而言,类是无关紧要的(不幸的是,在Class 对象上标记为同步锁的静态方法 - D'oh)。将锁视为另一个对象,每个对象都携带一个最终引用(这是一个糟糕的设计!),锁定一个对象并不意味着不受锁影响的代码无法访问该对象的字段。

标签: java multithreading synchronization locking


【解决方案1】:

首先,我认为你最好把类这个词从对话中去掉。假设您有两个对象o1o2,它们是实际上与讨论无关的类的实例,并且o1 具有对o2 的引用。

如果o1 同步实例o2 上的块,则没有其他线程可以进入同一实例o2 上的同步部分。这可以是o2 的非静态同步方法,也可以是请求锁定同一对象的任何同步块(假设有一个o3 对象也引用了o2 并希望对其进行同步, 直到o1 释放锁才会被阻塞)。

您可能会感到困惑的是同步方法周围的语法糖。同步方法只是编译器在您调用该方法的实际实例上添加一个同步块的方法,它涵盖了整个方法体。

public synchronized void synch1() {
   // body
}
// equivalent to:
public void synch2() {
   synchronized( this ) {
      // body
   }
}

如果您总是考虑同步块和用作锁的实际实例,那么在我看来事情就更简单了。一个线程可以锁定任何对象,两个线程不能访问被同一个对象锁定的同步区域。

【讨论】:

    【解决方案2】:

    获取一个锁 对象意味着没有其他线程可以 访问同步的代码 对象的类。

    这并不完全正确。如果代码在不同的对象实例上同步,则另一个线程可以执行属于对象类的同步代码。锁只限制在同一实例上同步的线程。

    现在,如果您谈论的是同步(非静态)方法,那么将被锁定的对象是被调用方法的this。但同样的规则也适用。

    现在假设我们已经同步 在 A 类的方法中阻塞获取 锁定 B 类的对象。所以让我们 说一个线程进入这个 同步块并已获取 特定对象的锁定 B类。

    如果任何其他线程使用相同的 B类的对象它将无法 进入同步块 A级,对吧?还有另一个 线程也不能访问任何 B 类中的同步代码?

    如果“其他线程”在 B 的同一个实例上同步,则第一部分是正确的。否则它是不正确的。

    第二部分不正确。只有在被阻塞的 B 的同一实例上同步的代码。

    【讨论】:

    • "只有在被阻塞的 B 的同一个实例上同步的代码。"因此,您的意思是,与 B 类对象同步的 A 类中的代码将被阻止。而如果B类本身有同步代码,会不会被阻塞?我有这个问题,因为它是我们正在获取的 B 类对象的锁。该锁也应该阻止类 B 中的同步代码。不是吗?
    • 没有。我的意思是只有在同一个 B 对象上同步时才会被阻止。关键是代码的位置无关紧要; 唯一重要的事情是您正在同步的对象。
    • 好的。因此,如果一个线程获得了一个对象上的锁,那么在该对象上同步的所有代码都将被阻塞在代码可能存在的任何地方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多