从openJDK几个项目看java未来发展
前言
java发展了几十年,一直是编程语言当中的主流语言。这与其本身的很多优秀特质是分不开的,例如:
- 强大的JVM: 让用户可以专注业务,让虚拟机自动化地管理内存。相比C、C++,这大大提升了工程效率
- 丰富的生态:作为一款发展25年以上的编程语言,使用其开发的软件不计其数,无论做什么工作,都能找到你需要的工具软件、三方包、学习资料等。
毫无疑问,java肯定是一门优秀的编程语言,但仍然有不足。很多后起之秀的编程语言也开始对java发起挑战。本文主要以java官方推进的项目展开来看看java当下的不足,以及未来发展的趋势。
java官方项目
这个可以在openJDK的官网上查阅到具体的project详情,可以点我查看。下图是其中关注度比较高的一些项目,本文接单做一些介绍。
Panama
github上可以查看项目。这个项目主要就是在jdk层面提供对别的语言更加高效方便的访问。可以做的事情诸如:
- 如你可以在java中通过jextract自动将c的header文件改写成java接口和方法
- 在java中更加方便的访问c的链接库,例如下图的unistd
- 调用其他语言的方法。参考下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 | // 通过花括号的结构来封装协程,代码块异步执行结束会自动等待 |
Structured Concurrency 核心在于通过一种 structured 的方法实现并发程序,用具有明确入口点和出口点的控制流结构来封装并发“线程”(可以是系统级线程也可以是用户级线程,也就是协程,甚至可以是进程)的执行,确保所有派生“线程”在出口之前完成。
Amber
amber项目主要是java语言本身层面的一些特性支持,参考他关联的一些JEP,例如record,var等。
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时,心中会更加的清晰。
参考资料
- 云原生时代,Java 的危与机
- 如何看待 JDK 17 新特性 JEP 410?
- 解决并发编程之痛的良药–结构化并发编程(高可用架构公众号)