专栏首页干货满满张哈希JEP解读与尝鲜系列4 - Java 16 中对于 Project Valhalla 的铺垫

JEP解读与尝鲜系列4 - Java 16 中对于 Project Valhalla 的铺垫

这是 JEP 解读与尝鲜系列的第 4 篇,之前的文章如下:

在系列之前的第一篇文章 - JEP 解读与尝鲜系列 1 - Java Valhalla 与 Java Inline class 中,我介绍了 Project Valhalla 项目中的核心 Java Inline Class,总结起来其实就是 Java 中的值类型。Java 中目前只有类对象,没有值类型的对象。普通的类对象有对象头,因此这种对象可以用来做同步锁,可以使用它的 wait() notify() 等方法实现阻塞同步,同时这些对象需要在堆上面分配,通过 JVM GC 进行内存回收。并且这种对象的数组,只有数组本身是内存连续的,上面引用的对象并不是:

Project Valhalla 提出并设计实现了 Java 的值类型,去掉了对象头,只存储它其中的值。这样减少了这种对象占用的空间,但是也让这种对象无法使用对象的 sychronization 同步,同时也失去了 对于**wait() notify()**这些方法的支持。同时这种对象期望是可以直接在栈上直接分配的,不用像普通对象一样需要在堆上分配,和原始类型例如 int 一样。同时这种对象的数组,期望在内存中数组的每个对象内存都是连续的:

这样也节省了指针的存储空间

但是这些目前还是在设计实现中,并不是最终的实现模型,但是可以看出其中的趋势。

为了能使 Project Valhalla 最终落地实现,我们先要对 JDK 的一些元素做兼容。

JDK 中的哪些类和值类型相关

首先,最先想到的就是 Java 的原始类型对应的封装类型,例如 java.lang.Integer。原始类型是可以也是需要改造成 Java 值类型的,但是需要避免项目中使用了 Integer 对象的 wait() notify(), notifyAll() 方法,或者将这个作为 synchronization 的对象。

然后想到的就是原子类,例如 java.util.concurrent.atomic.AtomicInteger。其实在 Java 9 之后的 JMM 模型中实现了更细粒度的访问控制,例如:

private int locked = 0;
private static final VarHandle LOCKED;
//操作 locked 的句柄
static {
	try {
		//初始化句柄
		LOCKED = MethodHandles.lookup().findVarHandle(当前类.class, "locked", int.class);
	} catch (Exception e) {
		throw new Error(e);
	}
}

//原子操作
LOCKED.compareAndSet(this, 1, 0);
LOCKED.weakCompareAndSet(this, 1, 0);
LOCKED.weakCompareAndSetAcquire(this, 1, 0);
LOCKED.weakCompareAndSetPlain(this, 1, 0);
LOCKED.weakCompareAndSetRelease(this, 1, 0);

然后还有在 Java 11 的官方文档中提出的 Value-based Classes,参考:Java 11 Value-based Classes,Java 11 中的定义是:像是 java.util.Optionaljava.time.LocalDateTime 这种类就是 Value-based Classes,这种类的实例:

  • 本身是不可变的,虽然内部的值引用指向的是一个可变对象
  • 实现了 equalshashCodetoString 方法,并且基于它包含的值实现,而不是基于他的 identity (例如对象基址)并且也不是基于其他对象的状态。
  • 不会使用 identity-sensitive 的操作,例如通过 == 对比两个实例的相等,使用默认的基于对象基址的 hashcode 实现(例如调用 System.identityHashCode(对象)),以及作为 synchronization 的对象
  • 只通过 equals 对比对象相等,而不是 ==
  • 没有可访问的构造函数,而是通过工厂方法实例化,这些方法对返回的实例的 identity 不做任何保证,即这个返回对象的地址我们无法通过对于工厂方法的传参确定;
  • equals 相等的两个对象,需要有完全相同的行为

这种 Value-based Classes 其实就与 Java 值类型的特征非常一致。于是,从 Java 16 开始,将 Value-based Classes 的定义进行了扩展,并且对它们的使用进行了报警限制,提示未来这些类型,不再使用普通类实现,而是使用 Project Valhalla 的 Java 值类型实现。

JEP 390: Warnings for Value-Based Classes

在 Java 16 中,为了给 Project Valhalla 的这一特性进行铺路,引入了一个 JEP:JEP 390: Warnings for Value-Based Classes

在最新的 Value-based Classes 的定义中(参考:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/doc-files/ValueBased.html ),将原始类型的封装类,例如 java.lang.Integer 也纳入了这一类的定义范畴。并在此基础上,增加两个说明:

1.非常不建议使用这一类的对象作为同步参数,例如 synchronize(obj),无法保证这个锁拥有者是谁以及是否是独占的

这个问题倒不是因为以后要换值类型无法同步导致的,而是容易犯这种编程失误:

Integer i = 1;

for (int j = 0; j < 10; j++) {
    synchronized(i) {
        i++; //下次循环就变成另一个对象了,没有真正按照预期锁住
    }
}

2.使用 identity 相关的操作可能未来会发生变化,所以不建议使用,例如:

  • 调用 System.identityHashCode(对象) 获取基于对象在堆内存地址实现的哈希码,如果 Value-based Classes 变成值类型,值类型确定在栈上分配后,这个方法目前的机制就会有问题。
  • 调用 synchronize(obj) 同步对象,如果 Value-based Classes 变成值类型,没有普通对象的对象头,那么无法使用正常的锁膨胀同步机制,同时重量锁 mutex 由于可能值类型对象没有堆上位置也无法使用现有的机制实现。
  • 调用对象的 wait()notify()notifyAll(),由于上一条同样的影响,这些方法调用可能在未来版本带来异常。

在 Java 16 之后,如果有这些用法,就会在编译阶段有报警提醒:

Integer integer = 1;
synchronized (integer) {
    
}

编译阶段会提示 Attempt to synchronize on an instance of a value-based class,如果想关闭可以增加编译参数 -Xlint:synchronization

如果想在运行阶段针对这种使用有提示或者错误,可以通过添加如下启动参数实现:

  • -XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=1:加上这个,程序遇到这种使用,会抛出 FATAL ERROR,同时退出 JVM
  • -XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=2:加上这个,程序遇到这种使用,会有日志提示:
[0.152s][info][valuebasedclasses] Synchronizing on object 0x000000069aed7788 of klass java.lang.Integer
[0.152s][info][valuebasedclasses] 	at com.github.hashjang.shenandoah.Main.main(Main.java:8)
[0.152s][info][valuebasedclasses] 	- locked <0x000000069aed7788> (a java.lang.Integer)

同样的,由于原始类型包装类已经属于 Value-based Class,所以就不应该使用它的构造器而是使用 valueOf() 代替了,为了给大家修改的时间,目前仅仅是将构造器标记为 Deprecate for Removal

@Deprecated(since="9", forRemoval = true)
public Integer(int value) {
    this.value = value;
}

如果有使用会提示 'Integer(int)' is deprecated and marked for removal

目前 JDK 中的未来可能会用值类型代替的 Value-based Classes

目前 JDK 中的 Value-based Classes 都带有 jdk.internal.ValueBased 注解,或者他们的实现接口,父类带有这个注解,包括:

  • java.lang 包:
    • 原始类型的封装类,例如 java.lang.Integer
    • java.lang.Runtime.Version
    • 操作系统进程的句柄 java.lang.ProcessHandle 和他的实现类 java.lang.ProcessHandleImpl
  • java.time 包下的一些时间封装类
  • java.util 包:
    • Optional 相关,例如:java.util.Optional, java.util.OptionalInt, java.util.OptionalLong, java.util.OptionalDouble
    • 所有不可变集合以及底层实现的不可变元素,例如:Set.of 的返回 java.util.ImmutableCollections.AbstractImmutableSet

一点趣事儿

Java 16 的 Record 还让我闹了个笑话,我以为这个是 Project Valhala 的 Inline Object 已经实现了,还去 StackOverflow 问,这个 Record 为啥能有 wait() 方法,并且可以进行 synchronized 同步(因为如果是 Project Valhala 的 Inline Object 的话是没有普通类的对象头的,没法用普通类对象的方法实现同步),结果。。。。。最后还是 Goetz 大佬一眼就看出我是误会了

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!
本文分享自作者个人站点/博客:https://zhanghaoxin.blog.csdn.net复制
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • JEP解读与尝鲜系列1 - Java Valhalla与Java Inline class

    最主要的一点就是,让Java适应现代硬件:在Java语言发布之初,一次内存访问和一次数字计算的消耗时间是差不多的,但是现在,一次内存访问耗时大概是一次数值计算的...

    干货满满张哈希
  • Inside Java Newscast #1 深度解读

    本文是 Inside Java Newscast #1 的个人体验与解读。视频地址:点击这里

    干货满满张哈希
  • Java18的新特性

    上面列出的是大方面的特性,除此之外还有一些api的更新及废弃,主要见JDK 18 Release Notes,这里举几个例子。

    code4it
  • Java18的新特性

    JDK17引入JEP 406: Pattern Matching for switch (Preview)[30] JDK18则作为第二轮的preview

    code4it
  • JDK 18 最新动态和 JDK 19 新特性预测

    JDK 18 是 JDK 17 之后第一个非 LTS 版本。按照甲骨文公司 Java 平台组首席架构师 Mark Reinhold 的说法,JDK 18 已进入...

    深度学习与Python
  • 实战 Java 16 值类型 Record - 1. Record 的默认方法使用以及基于预编译生成相关字节码的底层实现

    在之前的 JEP 尝鲜系列中,我们介绍了 Java Project Valhalla 以及 Java 值类型,经过 Java 14,15,16 的不断开发优化反...

    干货满满张哈希
  • 实战 Java 16 值类型 - 1. Record 的默认方法使用以及底层实现

    在之前的 JEP 尝鲜系列中,我们介绍了 Java Project Valhalla 以及 Java 值类型,经过 Java 14,15,16 的不断开发优化反...

    干货满满张哈希
  • Java没有创新了吗?Java 13提供可提高生产率和效率的功能

    在其CodeOne会议上,Oracle解释了Java SE 13正式发布后Java的快速发布周期如何带来创新。

    gemron的空间
  • Java没有创新了吗?Java 13提供可提高生产率和效率的功能

    在其CodeOne会议上,Oracle解释了Java SE 13正式发布后Java的快速发布周期如何带来创新。

    gemron的空间
  • 关于 Java 18 你想知道的一切

    Java 18 于今天(2022-3-22)发布 GA 版本了,今天也是我和我宝宝领证一周年的日子,为了纪念今天,特此奉上 - 关于 Java 18 你想知道的...

    干货满满张哈希
  • 关于 Spring-WebFlux 的一些想法

    现在基于 spring web 的同步微服务有一个非常大的缺陷就是:相对于基于 spring-webflux 的异步微服务,基于 spring-web 的同步微...

    干货满满张哈希
  • Java9的新特性

    java9大刀阔斧,重磅引入了模块化系统,自身jdk的类库也首当其冲模块化。新引入的jlink可以精简化jdk的大小,外加Alpine Linux的docker...

    code4it
  • Java 近期新闻:OpenJDK JEP、Spring 更新、Payara 平台和 Kotlin 1.6

    2021 年 11 月 15 日起始周 Java 新闻更新:OpenJDK JEP、JDK 18、Loom 项目、多个 Spring 单点版本、MicroPro...

    深度学习与Python
  • Java 近期新闻:Valhalla 项目的现状、GlassFish 7.0-M1 和 Loom Lab

    近期 Java 社区非常安静,但是 InfoQ 依然发现了一些值得关注的新闻,包括:Brian Goetz 撰写的由三部分组成的博客系列“Valhalla 项目...

    深度学习与Python
  • 来了来了,Java14它真的来了

    语言必须发展,否则它们就有变得无关紧要的风险,” Brian Goetz (甲骨文公司)在2019年11月在 Devoxx 举行的“ Java 语言期货”演讲中...

    麦洛
  • 来了来了,Java14 它真的来了!

    译文链接:https://blog.csdn.net/Milogenius/article/details/104997807

    逆锋起笔
  • Java 10的10个新特性,将彻底改变你写代码的方式!

    Java 9才发布几个月,很多玩意都没整明白,现在Java 10又要来了。。 这时候我真尼玛想说:线上用的JDK 7 甚至JDK 6,JDK 8 还没用熟,JD...

    Java技术栈
  • 这年头,能坐上火箭的东西不多啊!Java版本号算一个!

    Sun早已经不在了,如今只剩Oracle,也就是Java目前的抚养人。从2019年4月16号开始,Oracle版本的JDK,已经宣布收费,目前有更多的企业转向O...

    xjjdog
  • Java17的新特性

    上面列出的是大方面的特性,除此之外还有一些api的更新及废弃,主要见JDK 17 Release Notes,这里举几个例子。

    code4it

扫码关注腾讯云开发者

领取腾讯云代金券