Java 12正式发布,新特性解读!

作者 杨晓峰

Java 12如约而至,除了那些值得关注的特性,你也应该思考下Java的未来。

在Java 9之前,当一个版本被宣布为首选版本,存在一个“培育”(bedded-in)新GA版本的重叠期。在此期间,上一个版本将会继续进行免费更新。为确保新旧版本间的干净切换,即便旧版本已不再是首选版本,通常也会继续维护12个月以上。但是随着Java版本发布更改为遵循严格的时间表后,事实上宣告了传统的免费支持期将寿终正寝。

Oracle对Java 8的官方支持时间持续到2020年12月,之后将不再为个人桌面用户提供Oracle JDK 8的修复更新;在2019年1月之后,不再提供免费的商业版本更新,届时想要继续获得Oracle的商业支持和维护,需付费订阅。

Java是很多程序员的饭碗,Java生态圈下的程序员们似乎对于Oracle也有诸多不满,当Java也像Android系统走上版本号的稳定道路后,新版本的发布意义还有那么大吗?Java 12已经发布了,但使用版本最多的还是Java 8,你会选择升级吗?

JDK12如期而至,不知不觉Java半年为周期的发布模式(Half-year-cadence)已经成功运行了一年多,OpenJDK社区和Oracle充分展示了其坚决的执行力。今天当然要尝鲜JDK12的新特性,与此同时,笔者也会从不同角度,来分析新发布模式是否达到了其初衷。

下载地址:

https://www.oracle.com/technetwork/java/javase/downloads/index.html

JDK 12新特性一览:

189:Shenandoah: A Low-Pause-Time Garbage Collector (Experimental)

230:Microbenchmark Suite

325:Switch Expressions (Preview)

334:JVM Constants API

340:One AArch64 Port, Not Two

341:Default CDS Archives

344:Abortable Mixed Collections for G1

346:Promptly Return Unused Committed Memory from G1

首先值得关注的是Switch Expressions,这是一个为开发者准备的特性,我们可以利用具体代码快速了解一下,下面是传统statement形式的switch语法:

        switch(day){
            case MONDAY:
            case FRIDAY:
            case SUNDAY:
                    System.out.println(6);
                    break;
            case TUESDAY:
                    System.out.println(7);
                    break;
            case THURSDAY:
            case SATURDAY:
                    System.out.println(8);
                    break;
              case WEDNESDAY:
                    System.out.println(9);
                    break;

如果有编码经验,你一定知道,switch语句如果漏写了一个break,那么逻辑往往就跑偏了,这种方式既繁琐,又容易出错。如果换成switch表达式,Pattern Matching机制能够自然地保证只有单一路径会被执行,请看下面的代码示例:

        switch (day) {
                case MONDAY, FRIDAY, SUNDAY -> System.out.println(6);
                case TUESDAY -> System.out.println(7);
                case THURSDAY, SATURDAY -> System.out.println(8);
                case WEDNESDAY -> System.out.println(9);
        }

更进一步,下面的表达式,为我们提供了优雅地表达特定场合计算逻辑的方式

        int numLetters = switch (day) {
              case MONDAY, FRIDAY, SUNDAY -> 6;
              case TUESDAY -> 7;
              case THURSDAY, SATURDAY -> 8;
              case WEDNESDAY -> 9;
        };

Switch Expressions或者说起相关的Pattern Matching特性,为我们提供了勾勒出了Java语法进化的一个趋势,将开发者从复杂繁琐的低层次抽象中逐渐解放出来,以更高层次更优雅的抽象,既降低代码量,又避免意外编程错误的出现,进而提高代码质量和开发效率。

第二,则是很有现实意义度Shenandoah GC。它是Redhat主导开发的Pauseless GC实现,从大概2013年开始研发,终于取得了重要的阶段性成果,与其他Pauseless GC类似,Shenandoah GC主要目标是99.9%的暂停小于10ms,暂停与堆大小无关等。

也许了解Shenandoah GC的人比较少,业界声音比较响亮的是Oracle在JDK11中开源出来的ZGC,或者商业版本的Azul C4(Continuously Concurrent Compacting Collector)。但是,笔者认为,至少目前,其实际意义大于后两者,因为:

·使用ZGC的最低门槛是升级到JDK11,对很多团队来说,这种版本的跳跃并不是非常低成本的事情,更何况是尚不清楚ZGC在自身业务场景中的实际表现如何。

·而C4,毕竟是土豪们的选择,现实情况是,有多少公司连个几十块钱的License都不舍得…

·而Shenandoah GC可是有稳定的JDK8u版本发布的哦,据我所知已经有个别公司在HBase等高实时性产品中实践许久。

从原理的角度,我们可以参考该项目官方的示意图,其内存结构与G1非常相似,都是将内存划分为类似棋盘的region。整体流程与G1也是比较相似的,最大的区别在于实现了并发的Evacuation环节,引入的Brooks Forwarding Pointer技术使得GC在移动对象时,对象引用仍然可以访问。

下面是jbb15 benchmark中,Shenandoah GC相对于其他主流GC的表现,GC暂停相比于CMS等选择有数量级程度的提高,对于GC暂停非常敏感的场景,价值还是很明显的,能够在SLA层面有显著提高。当然,这种对于低延迟的保证,也是以消耗CPU等计算资源为代价的,实际吞吐量表现也不是非常明朗,需要看企业的实际场景需求,并不是一个一劳永逸的解决方案。

其他的一些特性,例如,G1相关的两个特性是对G1在特定场景不足的有效改进,但谈不上是突破性的提高,不再一一列举。

与JDK11这种长期支持版本(Long-Term-Support, LTS)相比,JDK12似乎关注度有限,大家对于JDK这种频繁的节奏也有点麻木了,那么:

·JDK12这种非LTS版本,是否有什么生产环境价值?

·Java新的发布模式是否达到了其快速落地和迭代新特性的目的?

也许不会有太多公司直接选择JDK12,但个别的生产实践并不遥远。比如,我所在部门在实践场景中发现,利用JDK 12的Abortable Mixed Collections for G1,解决了HDFS在特定场景中G1 Evacuation时间过长的困扰,虽然最后团队选择将其backport到了自己的JDK11版本中,但如果没有快速交付的预览版JDK12,也不会如此快速的得到结论。

而对另一个问题,笔者认为目前看是非常成功的,解开了Java/JVM演进的许多枷锁,至关重要的是,OpenJDK的权力中心,正在转移到开发社区和开发者手中。在新的模式中,既可以利用LTS满足企业长期可靠支持的需求,也可以满足各种开发者对于新特性迭代的诉求。你可能注意到了Switch Expressions被打上了预览(Preview)的标签,Shenandoah GC则是实验(Experimental)特性,这些都是以往的发布周期下不大现实的,因为用2-3年的最小间隔粒度来实验一个特性,基本是不现实的。

可以预计,JDK8在未来的一段时间仍将是主流,我们已经注意到Amazon、Alibaba、Redhat、AdoptOpenJDK等厂商或社区,纷纷发布了自己的JDK8等产品,开始竞赛长期支持版本JDK的主导权,笔者认为这是非常好的迹象,反映了主流厂商对于Java的投资力度增大。

是否会带来Java/JVM的碎片化呢?多少会发生一些,但从目前的合作模式来看,OpenJDK仍然是合作的中心,主导这Java历史版本维护和未来的演进路线。

一些小鲜肉语言嘲笑Java,实现类似功能,Java代码要多写近一倍,程序要笨重一个数量级,有些也许是言过其实,但语法的表达能力和JVM的庞大,确实逐渐成为Java发展的短板,JDK10~12发布的不间断成功,让我们看到了Java/JVM大踏步前进的曙光!