Java 为什么不锁定一个基于值的类呢

Java 为什么不锁定一个基于值的类呢,java,locking,java-8,Java,Locking,Java 8,假设您不应该锁定基于值的Java类的实例,例如Optional,因为 如果它试图区分对基于值的类的相等值的两个引用,则可能会产生不可预测的结果。。。间接地通过呼吁同步 断言 因为未来的JVM实现可能不会对基于值的类使用对象头和引用指针,所以一些限制是明确的。(例如,不锁定JVM必须不支持的标识。锁定的引用可能会被删除并在以后被另一个引用替换,这使得释放锁毫无意义,并将导致死锁) 也就是说,禁令是未来的证明。但这一论断没有参考依据 如果未来的打样是基础,我想为它提供一个参考。如果没有,我想了解基础

假设您不应该锁定基于值的Java类的实例,例如
Optional
,因为

如果它试图区分对基于值的类的相等值的两个引用,则可能会产生不可预测的结果。。。间接地通过呼吁同步

断言

因为未来的JVM实现可能不会对基于值的类使用对象头和引用指针,所以一些限制是明确的。(例如,不锁定JVM必须不支持的标识。锁定的引用可能会被删除并在以后被另一个引用替换,这使得释放锁毫无意义,并将导致死锁)

也就是说,禁令是未来的证明。但这一论断没有参考依据

如果未来的打样是基础,我想为它提供一个参考。如果没有,我想了解基础是什么,因为基于值的对象是
Object
s

编辑

顺便说一句,我理解不锁定整数和其他原始包装类的原因;它们可能被缓存。但我找不到任何文档说明基于值的类也是如此,尽管Integer等是基于值的,但它们是基于值的。即,&等明确表示

这是一个基于值的类


对于等,情况并非如此。

锁与对象相关联。如果对象是共享的,则可以共享它的锁。可以共享不可变的值类。理论上,对具有特定语义值的值对象的所有引用都可以引用一个共享对象。为值对象创建代码以重用值对象是很常见的。例如,通过缓存以前创建的值。因此,一般来说,当您有一个对值对象的引用时,您的代码应该能够正常工作,即使值对象也在其他地方使用。因此,不要将其用于锁定。

以下是作者的一篇关于基于值的类的博文:

在Java8中,值类型前面是基于值的类。它们在未来的精确关系尚不清楚,但可能类似于装箱和未装箱原语(例如整数和整数)。此外,编译器可能可以自由地在两者之间进行静默切换,以提高性能。确切地说,来回切换,即删除并稍后重新创建引用,也禁止将基于身份的机制应用于基于值的类

尼科莱的意思是:

  • 将来,编译器可能会以不保留对象标识的方式在值和基于值的类之间进行透明转换

  • 某些东西(“基于身份的机制”)依赖于对象身份。示例包括引用的
    ==
    语义、标识哈希代码、原语锁定和对象序列化

  • 对于这些事情,有可能是透明的翻译不会是透明的

在原语锁定的情况下,需要考虑的是可能会出现如下顺序

  • 将创建基于值的类的实例
  • 实例将在幕后转换为值
  • 然后将该值转换回另一个对象
  • 如果两个线程使用“实例”作为基本锁,那么它们可能不知道实际上有两个对象(现在)。如果他们随后尝试同步,他们将(可能)锁定不同的对象。这意味着,无论锁定的目的是保护哪个国家,都不存在相互排斥

    如果不锁定基于值的类,就不必担心潜在的危险。。。将来

    但请注意,Nicolai的博客帖子只是一个人对Java10或更高版本中可能发生的事情的猜测


    顺便说一句,我理解不锁定整数和其他原始包装类的原因;它们可能被缓存

    缓存本身不是问题,而是导致问题的一种机制。真正的问题是,很难对锁定对象的对象标识进行推理,从而判断锁定机制是否健全

    对于原始包装器,装箱和拆箱的语义导致了对象标识的不确定性。展望未来,有争议的价值类型对象转换将是这种不确定性的另一个来源


    上面的博客是基于它讨论如何为Java的未来版本添加值类型。本说明是一份立场声明,而不是一份完全规范(并通过)的提案。但是,该说明确实给了我们以下提示:

    上述许多限制与所谓基于值的类的限制相对应。事实上,似乎每种值类型的装箱形式都是基于值的类

    这可以理解为暗示值类型和现有基于值的类之间存在关系。(特别是当您阅读Java 8的描述时。)


    更新-2019/05/18

    值类型没有进入Java12,而且它们(还)不在Java13的列表中

    但是,已经可以演示与博客文章所述问题相关的问题:

        public class BrokenSync {
            private final Integer lock = 1;
    
            public void someMethod() {
                synchronized (lock) {
                    // do something
                }
            }
        }
    

    问题是,
    BrokenSync
    的每个实例都将通过自动装箱
    1
    创建一个
    Integer
    实例。但是JLS表示,自动装箱产生的
    Integer
    对象不一定是不同的对象。因此,您可以使用相同的
    Integer
    对象作为锁来结束
    BrokenSync
    的所有实例。

    所有需要的信息都在您引用的标题为“基于值的类”的页面上,尽管它没有写得那么清楚,也没有使用一些可以澄清这些问题的神奇短语<