【问题标题】:Purpose of different monitor objects in synchronized同步中不同监控对象的用途
【发布时间】:2019-04-09 16:29:03
【问题描述】:

谁能解释一下 synchronized(this) 和 synchronized(c) 之间的区别?

我参考了各种答案(1,2,3,4,5)但无法理解并感到困惑。

public class Check {

    Consumer c = new Consumer(null);

    public void getSynch() {

        synchronized (this) {
            // doing some task
            System.out.println("Start");
        }

        synchronized (c) {
            // doing some task
            System.out.println("End");
        }

    }

}

我能够理解同步的概念,但不能理解监控对象。请用简单的方式解释。

【问题讨论】:

  • thisc 是两个不同的对象。

标签: java


【解决方案1】:

synchronized 总是作用于监视器对象(有时也称为锁或信号量)。将其视为令牌:当线程进入同步块时,它会对令牌进行分级,其他线程需要等待令牌返回。如果您有多个不同的监视器对象,则基本上具有不同的令牌,因此在不同监视器上运行的同步块可以并行运行。

这有很多可能性,也有很多可能的用例。一种可能是一个类的多个实例可以并行运行,但需要访问共享的非线程安全资源。然后,您可以使用该资源或代表该资源“令牌”的任何其他对象作为监视器对象。

但是,请注意可能会出现死锁,例如在以下情况:

第 1 块:

synchronized(A) {
  //do something with A
  synchronized(B) {
    //do something with B
  }
}

第 2 块:

synchronized(B) {
  //do something with B
  synchronized(A) {
    //do something with A
  }
}

这里可以并行输入两个外部同步块,因为两个监视器 A 和 B 可用,但需要抓住另一个监视器,并且因为它们现在被锁定,所以两个线程都必须等待 - 类死锁。

还可以查看dining philosophers problem,它也处理该主题(这里的分叉可以被视为监视器对象)。

编辑:

在您的情况下(您发布的代码),多个线程可能会尝试在 Check 的同一实例上调用 getSynch()。第一个块在实例本身上同步,从而防止多个线程在同一个实例上调用时进入该块。

第二个块在c 上同步,这是一个不同的对象,可能会随着时间而改变。假设第一个块 (synchronized(this) { ... }) 更改 c 以引用 Consumer 的另一个实例。在这种情况下,您可以让多个线程并行运行该块,例如如果一个线程在另一个线程重新分配c 之前进入了synchronized(c) 块。

【讨论】:

  • 这里的参数是什么?一旦当前线程(Check)完成,只有 Check 线程的实例应该等待?
  • this 表示Check 的当前实例将用作监视器。理论上,多个线程可以在 same 实例上调用getSynch()Check 本身不是线程顺便说一句)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多