【问题标题】:Does Java `synchronized` block lock on Object reference, or value?Java `synchronized` 是否会阻塞对象引用或值的锁定?
【发布时间】:2017-07-25 16:00:45
【问题描述】:

给出如下所示的输出:

    Path path1 = Paths.get("/Users/someone/foo");
    Path path2 = Paths.get("/Users/someone/foo");
    System.out.println(path1.toString() == path2.toString()); // outputs false
    System.out.println(path1.toString().equals(path2.toString())); // outputs true

给定以下两个线程,是否有可能两个线程同时运行在临界区?

    // Thread 1
    synchronized (path1.toString()) {
        // Critical section
    }

    // Thread 2
    synchronized (path2.toString()) {
        // Critical section
    }

【问题讨论】:

  • 每个对象都有自己的监视器;这就是同步块获取的内容。因此,只有path1.toString() == path2.toString() 才会出现互斥。
  • 一般来说,同步方法调用的结果并不是一个好主意:即使你只在两个线程中同步path1.toString(),你可能根本不会得到互斥,如果它是总是返回一个新对象(你不知道是不是这样,它可以任意改变)。
  • 你当然不能指望这些引用是相同的。他们很可能不会。无论如何,你为什么要锁定StringString 携带大量运费和语义,仅用作锁定对象。你只需要一个Object

标签: java multithreading synchronization synchronized synchronized-block


【解决方案1】:

引用值。这是没有区别的区别。 toString() 是一个参考。它不会与任何其他 toString() 值相同,除非两者都已被实习,或者它们都源自相同或相同的字符串文字。

【讨论】:

  • 我认为 OP 想知道测试为相等的两个字符串(使用equals())是否足以确保线程安全。
  • @TedHopp 我认为推测他可能或可能不是什么意思没有任何意义。我正在回答他提出的问题。
  • 是的Ted,我想知道synchronized ()关键字中判断两个对象是否相等时是使用equals()还是==
  • @albusshin 那么你应该在你的问题中这么说。一旦你真正写下来,你就会发现它没有意义。为什么synchronized 会比较对象?
  • @albusshin 没有“东西”。这是一种方法。它比较它喜欢的任何东西,或者什么都不比较,然后返回一个值。
【解决方案2】:

正如Java Language Specification, section 14.19 (JLS) 中所述,synchronized 语句锁定对象。如果您将“值”视为字符串值(如path1.toString().equals(path2.toString())),那么答案是“否”——您的代码几乎肯定不是线程安全的。用 JLS 的说法,如果表达式的 type 是引用类型(正如 synchronized 语句所要求的那样),那么该表达式的 valuenull 或一个对象。除非两个 toString() 调用返回相同的对象引用 (path1.toString() == path2.toString()),否则您发布的代码中的两个块不是互斥的。

【讨论】:

  • 这与引用的参考文献告诉我们的相反。它说,“否则,让表达式的非空值是 V。执行线程锁定与 V 关联的监视器。”它锁定与表达式关联的监视器,而不是此答案所声称的引用。此外,正如 §17.1 所述,监视器与对象相关联,而不是与引用相关联。 “Java 中的每个对象都与一个监视器相关联,线程可以锁定或解锁监视器。”
  • @LewBloch 这又是一个没有区别的区别。它是一个引用值表达式。
  • 说 JLS 的反面确实会有所作为,特别是当它解决 OP 提出的确切问题并给出相反的答案时。不仅如此,您只需阅读类似这样的论坛几分钟,就可以看到对象和引用(指针)之间的混淆造成了多大的损害。它在锁、GC、多态性、复制和克隆、不变性、参数传递(以及是否按值传递)方面都很重要——真的是一切。因此,您声称这是“没有区别的区别”与它试图捍卫的答案一样与真理相反。
  • @LewBloch - 公平点。我稍微更新了我的措辞,以澄清 Java 锁定对象,而不是引用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 2013-01-16
  • 1970-01-01
  • 1970-01-01
  • 2014-06-10
  • 1970-01-01
相关资源
最近更新 更多