从openJDK几个项目看java未来发展

前言

java发展了几十年,一直是编程语言当中的主流语言。这与其本身的很多优秀特质是分不开的,例如:

  • 强大的JVM: 让用户可以专注业务,让虚拟机自动化地管理内存。相比C、C++,这大大提升了工程效率
  • 丰富的生态:作为一款发展25年以上的编程语言,使用其开发的软件不计其数,无论做什么工作,都能找到你需要的工具软件、三方包、学习资料等。

毫无疑问,java肯定是一门优秀的编程语言,但仍然有不足。很多后起之秀的编程语言也开始对java发起挑战。本文主要以java官方推进的项目展开来看看java当下的不足,以及未来发展的趋势。

java官方项目

这个可以在openJDK的官网上查阅到具体的project详情,可以点我查看。下图是其中关注度比较高的一些项目,本文接单做一些介绍。
image.png

Panama

github上可以查看项目。这个项目主要就是在jdk层面提供对别的语言更加高效方便的访问。可以做的事情诸如:

  • 如你可以在java中通过jextract自动将c的header文件改写成java接口和方法
  • 在java中更加方便的访问c的链接库,例如下图的unistd

image.png

  • 调用其他语言的方法。参考下JNI做的事情,panama使得这种调用更加容易,这样可以利用c和c++的库做一些方便的native调用

Valhalla

Java一切皆对象的理念对于工程化是很有帮助的,但是处理一系列类型不同的小对象时性能十分拉胯。Valhalla项目就是通过引入值对象来改善这一问题,使得java在游戏、图形领域也能有强的竞争力。

JIT从JDK6开始就通过逃逸分析来做做标量替换(Scalar Replacement)和栈上分配(Stack Allocations)来优化性能。即在对象不会传递到方法外的时候不创建完整对象布局,通过更加紧凑、平摊的方式分配内存提升CPU处理的效率。这里可以横向对比下c和c++中的struct,其实本质是值对象,不会有java开销较高的类对象内存布局。

原生的值类型带来如下好处:

  • 节约内存、性能更好:更加紧凑的内存分配,很多时候可以直接做cache line优化,避免频繁访问ram,陷入冯诺依曼瓶颈
  • 泛型支持原生类型
  • 统一Integer和int,在语言层面避免拆装箱

了解更加详细的valhalla背景可以看下下面文章:State of Valhalla

Loom

该项目旨在拓展jdk 1:1的线程模型,引入协程(coroutine)。以前jdk的线程模型和操作系统线程1:1对应,适合CPU密集型任务,但是对于需要大量线程的I/O密集型任务,过重的线程开销和频繁的上下文切换对性能开销都比较大。

除了引入协程,还有个重点是支持结构化并发的编程范式(2016年ZerMQ作者提出),这将大大简化并发编程使用的门槛,减少出错概率。简而言之这种结构化编程理念即“Code like sync,Work like async”。下面给出一个例子:

1
2
3
4
5
6
// 通过花括号的结构来封装协程,代码块异步执行结束会自动等待
ThreadFactory factory = Thread.builder().virtual().factory();
try (var executor = Executors.newThreadExecutor(factory)) {
executor.submit(task1);
executor.submit(task2);
} // blocks and waits

Structured Concurrency 核心在于通过一种 structured 的方法实现并发程序,用具有明确入口点和出口点的控制流结构来封装并发“线程”(可以是系统级线程也可以是用户级线程,也就是协程,甚至可以是进程)的执行,确保所有派生“线程”在出口之前完成。

Amber

amber项目主要是java语言本身层面的一些特性支持,参考他关联的一些JEP,例如record,var等。
image.png

Leyden

这个项目成立是为了解决java启动慢的问题。用java写过大型项目的同学都有体会,java重启的过程还是比较重的,其中主要开销是类的加载连接初始化。java是解释+JIT一起工作的,leyden项目的目的就是替换老的这种方式,称之为static-image,相比传统AOT只是直接把代码编译成机器码,static-image除了把代码编译成机器码,还会把runtime信息一起编译成机器码,在运行时能够完整运行。

类似使用static-image这样技术的项目还有GraalVM

思考:为什么云原生golang的应用更具优势?

  • 云原生技术本质是操作系统虚拟化,golang相比更加native,对操作系统的调用更加直接
  • 微服务、大量容器,golang内存更有优势:java解释器+JIT的模式内存开销更多。

采用类AOT的提前编译负面影响

  • 提前编译影响类的动态加载
  • 反射无法工作:反射原本可以调用编译期不可知的方法,现在也无法做到
  • 动态代理
  • 字节码生成
  • 元编程能力弱,复杂工程代码可能会越来越臃肿

这些影响,都需要对应的项目去解决

tips: 从当前发展来看,oracle lab独立维护的graalVM可能是这个赛道上的胜出者

Portola

主要是jdk对Alpine Linux的支持。Alpine Linux基础镜像5MB,是很多容器首选镜像。Alpine Linux不使用GUN C还是用musl作为C标准库,JDK主要是适配这块。

Portola项目使得jdk能够被更好地应用于容器环境。

总结

总的来说java仍然是一门非常有潜力的原因,尽管他有这样那样的不好,但是他也一直在变得更好。在深入了解过各个jdk projects以后,后续看不同JDK的发布以及他们关联的JEP时,心中会更加的清晰。

参考资料