国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

JDK8到JDK17有哪些吸引人的新特性?

這篇具有很好參考價(jià)值的文章主要介紹了JDK8到JDK17有哪些吸引人的新特性?。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

作者:京東零售?劉一達(dá)

前言

2006年之后SUN公司決定將JDK進(jìn)行開(kāi)源,從此成立了OpenJDK組織進(jìn)行JDK代碼管理。任何人都可以獲取該源碼,并通過(guò)源碼構(gòu)建一個(gè)發(fā)行版發(fā)布到網(wǎng)絡(luò)上。但是需要一個(gè)組織審核來(lái)確保構(gòu)建的發(fā)行版是有效的, 這個(gè)組織就是JCP(Java Community Process)。2009年,SUN公司被Oracle公司"白嫖"(參考2018年Google賠款),此時(shí)大家使用的JDK通常都是Oracle公司的OpenJDK構(gòu)建版本-OracleJDK。但是,Oracle公司是一個(gè)明顯只講商業(yè)而不管情懷的公司,接手Java商標(biāo)之后,明顯加快了JDK的發(fā)布版本。2018年9月25日,JDK11成功發(fā)布,這是一個(gè)LTS版本,包含了17個(gè)JEP的更新。與此同時(shí),Oracle把JDK11起以往的商業(yè)特性全部開(kāi)源給OpenJDK(例如:ZGC和Flight Recorder)。根據(jù)Oracle的官方說(shuō)法(Oracle JDK Releases for Java 11 and Later),從JDK11之后,OracleJDK與OpenJDK的功能基本一致。然后,Oracle宣布以后將會(huì)同時(shí)發(fā)行兩款JDK:1. 一個(gè)是以GPLv2+CE協(xié)議下,由Oracle發(fā)行OpenJDK(簡(jiǎn)稱為Oracle OpenJDK);2. 另一個(gè)是在OTN協(xié)議下的傳統(tǒng)OracleJDK。這兩個(gè)JDK共享絕大多數(shù)源碼,核心差異在于前者可以免費(fèi)在開(kāi)發(fā)、測(cè)試和生產(chǎn)環(huán)境下使用,但是只有半年時(shí)間的更新支持。后者各個(gè)人可以免費(fèi)使用,但是生產(chǎn)環(huán)境中商用就必須付費(fèi),可以有三年時(shí)間的更新支持。
2021年9月14日,Oracle JDK17發(fā)布,目前也是最新的Java LTS版本。有意思的是,Oracle竟然"朝令夕改",OracleJDK17竟然是免費(fèi)的開(kāi)源協(xié)議,并支撐長(zhǎng)達(dá)8年的維護(hù)計(jì)劃。目前公司內(nèi)部使用的OracleJDK8最高版本為1.8.0.192,而Oracle在JDK8上開(kāi)源協(xié)議支持的最高免費(fèi)版本為jdk1.8.0_202。2022年Spring6和SpringBoot3相繼推出,而支持的最低版本為JDK17。綜上所述,JDK8為目前絕大多數(shù)以穩(wěn)定性為主的系統(tǒng)第一選擇,但是升級(jí)到高版本JDK也只是時(shí)間問(wèn)題。下面圖表展示了JDk8到JDK17的每個(gè)版本升級(jí)的JEP個(gè)數(shù)。

通過(guò)以上圖表,我們可以得出結(jié)論,JDK8到JDK17包含大量新特性,為Oracle在Java近5年來(lái)的智慧結(jié)晶。目前市面上的公司還是只有少數(shù)系統(tǒng)會(huì)選擇JDK11或者JDK17作為線上技術(shù)選型,如果選擇從JDK8升級(jí)到JDK17必然會(huì)有非常大的挑戰(zhàn)和較多需要填的坑。本文主要介紹JDK8到JDk17近200個(gè)JEP中比較有價(jià)值的新特性(按照價(jià)值從高到低排序),這里有一部分特性作者也在線上環(huán)境使用過(guò),也會(huì)將其中的使用心得分享給大家。

核心JEP功能及原理介紹

一、Java平臺(tái)模塊化系統(tǒng)(Jigsaw項(xiàng)目)

JDK9最耀眼的新特性就是Java平臺(tái)模塊化系統(tǒng)(JPMS,Java Platform Module System),通過(guò)Jigsaw項(xiàng)目實(shí)施。Jigsaw項(xiàng)目是Java發(fā)展過(guò)程的一個(gè)巨大里程碑,Java模塊系統(tǒng)對(duì)Java系統(tǒng)產(chǎn)生非常深遠(yuǎn)的影響。與JDK的函數(shù)式編程和 Lamda表達(dá)式存在本質(zhì)不同 ,Java模塊系統(tǒng)是對(duì)整個(gè)Java生態(tài)系統(tǒng)做出的改變。

同時(shí)也是JDK7到JDK9的第一跳票王項(xiàng)目。Jigsaw項(xiàng)目本計(jì)劃于在2010年伴隨著JDK7發(fā)布,隨著Sun公司的沒(méi)落及Oracle公司的接手,Jigsaw項(xiàng)目從JDK7一直跳票到JDK9才發(fā)布。前后經(jīng)歷了前后將近10年的時(shí)間。即使在2017JDK9發(fā)布前夕,Jigsaw項(xiàng)目還是差點(diǎn)胎死腹中。原因是以IBM和Redhat為首的13家企業(yè)在JCP委員會(huì)上一手否決了Jigsaw項(xiàng)目作為Java模塊化規(guī)范進(jìn)入JDK9發(fā)布范圍的規(guī)劃。原因無(wú)非就是IBM希望為自己的OSGI技術(shù)在Java模塊化規(guī)范中爭(zhēng)取一席之地。但是Oracle公司沒(méi)有任何的退讓,不惜向JCP發(fā)去公開(kāi)信,聲稱如果Jigsaw提案無(wú)法通過(guò),那么Oracle將直接自己開(kāi)發(fā)帶有Jigsaw項(xiàng)目的java新版本。經(jīng)歷了前后6次投票,最終JDK9還是帶著Jigsaw項(xiàng)目最終發(fā)布了。但是,令人失望的是,Java模塊化規(guī)范中還是給Maven、Gradle和OSGI等項(xiàng)目保留了一席之地。對(duì)于用戶來(lái)說(shuō),想要實(shí)現(xiàn)完整模塊化項(xiàng)目,必須使用多個(gè)技術(shù)相互合作,還是增加了復(fù)雜性。如果大家想要對(duì)模塊化技術(shù)有更多深入了解,推薦閱讀書籍《Java9模塊化開(kāi)發(fā):核心原則與實(shí)踐》

1、什么是Java模塊化?

簡(jiǎn)單理解,Java模塊化就是將目前多個(gè)包(package)組成一個(gè)封裝體,這個(gè)封裝體有它的邏輯含義 ,同時(shí)也存在具體實(shí)例。同時(shí)模塊遵循以下三個(gè)核心原則:

  1. 強(qiáng)封裝性:一個(gè)模塊可以選擇性的對(duì)其他模塊隱藏部分實(shí)現(xiàn)細(xì)節(jié)。

  2. 定義良好的接口:一個(gè)模塊只有封裝是不夠的,還要通過(guò)對(duì)外暴露接口與其他模塊交互。因此,暴露的接口必須有良好的定義。

  3. 顯示依賴:一個(gè)模塊通常需要協(xié)同其他模塊一起工作,該模塊必須顯示的依賴其他模塊 ,這些依賴關(guān)系同時(shí)也是模塊定義的一部分。

2、為什么要做模塊化?

模塊化是分而治之的一個(gè)重要實(shí)踐機(jī)制,微服務(wù)、OSGI和DDD都可以看到模塊化思想的影子。現(xiàn)在很多大型的Java項(xiàng)目都是通過(guò)maven或者gradle進(jìn)行版本管理和項(xiàng)目構(gòu)建,模塊的概念在Maven和gradle中早就存在,兩者的不同下文也會(huì)說(shuō)到?,F(xiàn)在讓我們一起回顧一下目前在使用JDK搭建復(fù)雜項(xiàng)目時(shí)遇到的一些問(wèn)題:

2.1 如何使得Java SE應(yīng)用程序更加輕量級(jí)的部署?

java包的本質(zhì)只不過(guò)是類的限定名。jar包的本質(zhì)就是將一組類組合到一起。一旦將多個(gè)Jar包放入ClassPath,最終得到只不過(guò)是一大堆文件而已。如何維護(hù)這么龐大的文件結(jié)構(gòu)?目前最有效的方式,也是只能依賴mave或者gradle等項(xiàng)目構(gòu)建工具。那最底層的Java平臺(tái)的Jar包如何維護(hù)?如果我只是想部署一個(gè)簡(jiǎn)答的 helloworld應(yīng)用,我需要一個(gè)JRE和一個(gè)用戶編譯的Jar包,并將這個(gè)Jar包放到classpath中去。JDK9以前,JRE的運(yùn)行依賴我們的核心java類庫(kù)-rt.jar。rt.jar是一個(gè)開(kāi)箱即用的全量java類庫(kù),要么不使用,要么使用全部。直到JDK8,rt.jar的大小為60M,隨著JDK的持續(xù)發(fā)展,這個(gè)包必然會(huì)越來(lái)越大。而且全量的java類庫(kù),給JRE也帶來(lái)了額外的性能損耗。Java應(yīng)用程序如果能選擇性的加載rt.jar中的文件該多好?

2.2 在暴露的JAR包中,如何隱藏部分API和類型?

在使用Dubbo等RPC框架中,provider需要提供調(diào)用的接口定義Jar包,在該Jar包中包含一個(gè)共該Jar包內(nèi)部使用的常量聚合類Constannt,放在constant包內(nèi)。如何才能暴露JAR包的同時(shí),隱藏常量聚合類Constant?

2.3 一直遭受NoClassDefFoundError的折磨

通過(guò)什么方式,可以知道一個(gè)Jar包依賴了哪些其他的 Jar包?JDK本身目前沒(méi)有提供,可以通過(guò)Maven工具完成。那為什么不讓Java平臺(tái)自身就提供這些功能?

3、JPMS如何解決現(xiàn)有問(wèn)題?

JPMS具有兩個(gè)重要的目標(biāo):

  1. 強(qiáng)封裝(Strong encapsulation): 每一個(gè)模塊都可以聲明了哪些包是對(duì)外暴露的,java編譯和運(yùn)行時(shí)就可以實(shí)施這些規(guī)則來(lái)確保外部模塊無(wú)法使用內(nèi)部類型。

  2. 可靠配置(Reliable configuration):每一模塊都聲明了哪些是它所需的,那么在運(yùn)行時(shí)就可以檢查它所需的所有模塊在應(yīng)用啟動(dòng)運(yùn)行前是否都有。

Java平臺(tái)本身就是必須要進(jìn)行模塊化改造的復(fù)雜項(xiàng)目,通過(guò)Jigsaw項(xiàng)目落地。

3.1 Project Jigsaw

Modular development starts with a modular platform. —Alan Bateman 2016.9

模塊化開(kāi)始于模塊化平臺(tái) 。Project Jigsaw 有如下幾個(gè)目標(biāo):

  1. 可伸縮平臺(tái)(Scalable platform):逐漸從一個(gè)龐大的運(yùn)行時(shí)平臺(tái)到有有能力縮小到更小的計(jì)算機(jī)設(shè)備。

  2. 安全性和可維護(hù)性(Security and maintainability):更好的組織了平臺(tái)代碼使得更好維護(hù)。隱藏內(nèi)部API和更明確的接口定義提升了平臺(tái)的安全性。

  3. 提升應(yīng)用程序性能(Improved application performance):只有必須的運(yùn)行時(shí)runtimes的更小的平臺(tái)可以帶來(lái)更快的性能。

  4. 更簡(jiǎn)單的開(kāi)發(fā)體驗(yàn)Easier developer experience:模塊系統(tǒng)與模塊平臺(tái)的結(jié)合使得開(kāi)發(fā)者更容易構(gòu)建應(yīng)用和庫(kù)。

對(duì)Java平臺(tái)進(jìn)行模塊化改造是一個(gè)巨大工程,JDK9之前,rt.jar是個(gè)巨大的Java運(yùn)行時(shí)類庫(kù),大概有60MB左右。JDK9將其拆分成90個(gè)模塊左右 ,如下圖所示(圖片來(lái)源《Java 9模塊化開(kāi)發(fā)》):

4 創(chuàng)建第一個(gè)Java模塊

創(chuàng)建一個(gè)Java模塊其實(shí)非常的簡(jiǎn)單。在目前Maven結(jié)構(gòu)的項(xiàng)目下,只需要在java目錄下,新建一個(gè)module-info.java文件即可。此時(shí),當(dāng)前目錄就變成了一個(gè)Java模塊及Maven模塊。

--moudule1
---src
----main
-----java
------com.company.package1
------moudule-info.java
---pom.xml

5 模塊化對(duì)現(xiàn)有應(yīng)用的影響

5.1 你可以不用但是不能不懂

Java模塊化目前并沒(méi)有展現(xiàn)出其宣傳上的影響,同時(shí)也鮮有類庫(kù)正在做模塊化的改造。甚至,本人在創(chuàng)建第一個(gè)模塊的時(shí)候,就遇到了Lombook失效、深度反射失敗、Spring啟動(dòng)失敗以及無(wú)法動(dòng)態(tài)部署的影響。因此,盡量不要嘗試在線上環(huán)境使用模塊化技術(shù)!不用,但是不代表你可以不懂!隨著Java平臺(tái)模塊化的完成,運(yùn)行在JDK9環(huán)境的Java程序就已經(jīng)面臨著Jar包和模塊的協(xié)作問(wèn)題。未雨綢繆,在發(fā)現(xiàn)問(wèn)題的時(shí)候,模塊化技術(shù)可以幫你快速的定位問(wèn)題并解決問(wèn)題。
例如,在從JDK8升級(jí)到JDK11時(shí),我們經(jīng)常會(huì)收到一下警告:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.jd.jsf.java.util.GregorianCalendar_$$_Template_1798100948_0 (file:/home/export/App/deliveryorder.jd.com/WEB-INF/lib/jsf-1.7.2.jar) to field java.util.Calendar.fields
WARNING: Please consider reporting this to the maintainers of com.jd.jsf.java.util.GregorianCalendar_$$_Template_1798100948_0
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

通過(guò)反射訪問(wèn)JDK模塊內(nèi)類的私有方法或?qū)傩裕耶?dāng)前模塊并未開(kāi)放指定類用于反射訪問(wèn),就會(huì)出現(xiàn)以上告警。解決方式也必須使用模塊化相關(guān)知識(shí),可以使用遵循模塊化之間的訪問(wèn)規(guī)則,也可以通過(guò)設(shè)置 –add-opens java.base/java.lang = ALL-UNNNAMED 破壞模塊的封裝性方式臨時(shí)解決;

5.2 Java模塊、Maven模塊和OSGI模塊的之間的關(guān)系。

Java模塊化技術(shù),理論上可以從Java底層解決模塊和模塊之間的模塊依賴、多版本、動(dòng)態(tài)部署等問(wèn)題。 前文所述,在2017JDK9發(fā)布前夕,以IBM和Redhat為首的13家企業(yè)在JCP委員會(huì)上一手否決了Jigsaw項(xiàng)目作為Java模塊化規(guī)范進(jìn)入JDK9發(fā)布范圍的規(guī)劃。經(jīng)過(guò)眾多權(quán)衡,Java模塊化規(guī)范中還是給Maven、Gradle和OSGI等項(xiàng)目保留了一席之地。目前,可以通過(guò)Java模塊+Maven模塊或者Java模塊+OSGI模塊的方式構(gòu)建項(xiàng)目,可惜的是,使用多個(gè)技術(shù)相互合作,還是增加了復(fù)雜性。

5.3 模塊化對(duì)類加載機(jī)制的影響

JDK9之后,首先取消了之前的擴(kuò)展類加載器,這是清理之中,因?yàn)楸旧鞪RE擴(kuò)展目錄都已經(jīng)不存在,取而代之的是平臺(tái)類加載器。然后,類加載器的雙親委派模型機(jī)制進(jìn)行了破壞,在子類將類委派給父類加載之前,會(huì)優(yōu)先將當(dāng)前類交給當(dāng)前模塊(Moudle)或?qū)樱↙ayer)的類加載器加載。所以會(huì)形成如下的類加載模型:

同時(shí),在JDK9之后,引入的層(Layer)的概念,在Java程序啟動(dòng)時(shí),會(huì)解析當(dāng)前模塊路徑中的依賴關(guān)系,并形成一個(gè)依賴關(guān)系圖包含在引導(dǎo)層(Bootstrap Layer)中,這個(gè)依賴關(guān)系圖從此開(kāi)始不再改變。因此,現(xiàn)在動(dòng)態(tài)的新增模塊要?jiǎng)?chuàng)建新的層,不同的層之間可以包含相同的模塊。會(huì)形成如下所示的依賴關(guān)系(圖片來(lái)源《Java 9模塊化開(kāi)發(fā)》):

綜上所述,模塊化改造對(duì)于使用自定義類加載器進(jìn)行功能動(dòng)態(tài)變化的程序還是巨大的,一旦使用模塊化,必然會(huì)導(dǎo)致這類功能受到巨大影響。當(dāng)然模塊化技術(shù)普及還需要很長(zhǎng)一段時(shí)間,會(huì)晚但是不會(huì)不來(lái),提前掌握相關(guān)技術(shù)還是很必要。

5.4 總結(jié)

下面是Java模塊化相關(guān)技術(shù)的一些核心腦圖,可以學(xué)習(xí)參考:

二、垃圾回收器的一系列優(yōu)化措施

2.1、ZGC-新一代垃圾回收器

JDK11中,最耀眼的新特性就是ZGC垃圾回收器。作為實(shí)驗(yàn)性功能,ZGC的特點(diǎn)包括:

  • GC停頓時(shí)間不會(huì)超過(guò)10ms。

  • 停頓時(shí)間不會(huì)隨著堆的大小,或者活躍對(duì)象的大小而增加;

  • 相對(duì)于G1垃圾回收器而言,吞吐量降低不超過(guò)15%;

  • 支持Linux/x64、window和mac平臺(tái);

  • 支持8MB~16TB級(jí)別的堆回收。

同時(shí)根據(jù)openJDK官方的性能測(cè)試數(shù)據(jù)顯示(JEP333),ZGC的表現(xiàn)非常的出色:

  • 在僅關(guān)注吞吐量指標(biāo)下,ZGC超過(guò)了G1;

  • 在最大延遲不超過(guò)某個(gè)設(shè)定值(10到100ms)下關(guān)注吞吐量,ZGC較G1性能更加突出。

  • 在僅關(guān)注低延遲指標(biāo)下,ZGC的性能高出G1將近兩個(gè)數(shù)量級(jí)。99.9th僅為G1的百分之一。

也正是因?yàn)槿绱耍琙GC簡(jiǎn)直是低延遲大內(nèi)存服務(wù)的福音。話說(shuō)如此,作者在嘗試使用ZGC過(guò)程中還是發(fā)現(xiàn)一些問(wèn)題:

  1. 因?yàn)檎麄€(gè)ZGC周期基本都是并發(fā)執(zhí)行,因此創(chuàng)建新對(duì)象的速度與垃圾回收的速度從一開(kāi)始就在較量。如果創(chuàng)建新對(duì)象的速度更勝一籌,垃圾會(huì)將堆占滿導(dǎo)致部分線程阻塞,直到垃圾回收完畢。

  2. G1雖然是第一個(gè)基于全局的垃圾回收器,但是仍然存在新生代和老年代的概念。但是從ZGC開(kāi)始,完全拋棄了新生代和老年代。但是新生代對(duì)象朝生夕滅的特性會(huì)給ZGC帶來(lái)很大的壓力。完全的并發(fā)執(zhí)行,必然會(huì)造成一定的吞吐量降低。

  3. 在JDK11,G1垃圾回收器目前還只是實(shí)驗(yàn)性的功能,只支持Linux/x64平臺(tái)。后續(xù)優(yōu)化接改進(jìn),短時(shí)間內(nèi)無(wú)法更新到JDK11中,所以可能會(huì)遇到一些不穩(wěn)定因素。例如: 1. JDK12支持并發(fā)類卸載功能。2. JDK13將可回收內(nèi)存從4TB支持到16TB。3. JDK14提升穩(wěn)定性的同時(shí),提高性能。4. JDK15從實(shí)驗(yàn)特性轉(zhuǎn)變?yōu)榭缮a(chǎn)特性 。所以如果想要使用穩(wěn)定的ZGC功能,只能升級(jí)到JDK17,橫跨一個(gè)JDK11LTS版本,同時(shí)面臨近200個(gè)JEP帶來(lái)的功能更新。

  4. 實(shí)際線上生產(chǎn)環(huán)境,在訂單商品等核心系統(tǒng)嘗試使用ZGC。但是壓測(cè)結(jié)果顯示,在JDK11還是JDK17都差強(qiáng)人意。當(dāng)然這并不是代表ZGC本身技術(shù)缺陷,而是需要根據(jù)不同的線上環(huán)境做更深度的調(diào)優(yōu)和實(shí)踐。因?yàn)閿?shù)據(jù)保密等原因,這里沒(méi)有給大家展示具體的壓測(cè)數(shù)據(jù),讀者可以在各自環(huán)境進(jìn)行不同程度的壓測(cè)驗(yàn)證。

ZGC的原理介紹需要極大的篇幅,本文不打算對(duì)ZGC的底層技術(shù)展開(kāi)大范圍討論。如果大家想要深入學(xué)習(xí),作者推薦書籍《新一代垃圾回收器ZGC設(shè)計(jì)與實(shí)現(xiàn)》、Openjdk官網(wǎng):ZGC介紹以及《深入理解Java虛擬機(jī)第五版》中的一些介紹。

2.2、G1垃圾回收器相關(guān)

總的來(lái)講,得益于多個(gè)JEP優(yōu)化,G1垃圾回收器無(wú)論是在JDK11還是JDK17都表現(xiàn)出了更強(qiáng)大的能力。隨著CMS垃圾回收器的廢棄,以及新生代ZGC的初出茅廬,G1垃圾回收器毫無(wú)疑問(wèn)成了兼顧延遲和吞吐的最佳選擇。通過(guò)多次壓測(cè)結(jié)果觀察,只是簡(jiǎn)單的提高JDK版本,就可以做到更低的GC時(shí)間、更短的GC間隔以及更少的CPU損耗。

場(chǎng)景 JDK 并發(fā) 基線參考 TPS TPM TP99 TP999 TP9999 MAX CPU
1.8.0_192 20 -Xms12g -Xmx12g -XX:+UseG1GC -XX:ParallelGCThreads=13 -XX:ConcGCThreads=4 1680 97640 10 28 31 32 50.07%
11.0.8 20 -Xms12g -Xmx12g -XX:+UseG1GC -XX:ParallelGCThreads=13 -XX:ConcGCThreads=4 1714 99507 10 23 27 29 49.35%

2.2.1、G1的Full GC從串行改為并行(JEP307)

? G1垃圾回收器,在 Mix GC回收垃圾的速度小于新對(duì)象分配的速度時(shí),會(huì)發(fā)生Full GC。之前,發(fā)生Full GC時(shí)采用的是Serial Old算法,該算法使用單線程標(biāo)記-清除-壓縮算法,垃圾回收吞吐量較高,但是Stop-The-World時(shí)間變長(zhǎng)。JDK10,為了減少G1垃圾回收器在發(fā)生Full GC時(shí)對(duì)應(yīng)用造成的影響,F(xiàn)ull GC采用并行標(biāo)記-清除-壓縮算法。該算法可以通過(guò)多線程協(xié)作 ,減少Stop-The-World時(shí)間。線程的數(shù)量可以由-XX:ParallelGCThreads選項(xiàng)來(lái)配置 ,但是這也會(huì)影響Young GC和Mixed GC線程數(shù)量。

2.2.2、可中斷的Mixed-GC(JEP344)

G1垃圾回收器,通過(guò)一種名為CSet的數(shù)據(jù)結(jié)構(gòu)輔助實(shí)現(xiàn)可預(yù)測(cè)停頓模型算法。CSet中存儲(chǔ)了GC過(guò)程中可進(jìn)行垃圾回收的Region集合。在本特性之前,CSet一旦被確定,就必須全部掃描并執(zhí)行回收操作,這可能會(huì)導(dǎo)致超過(guò)預(yù)期的垃圾回收暫停時(shí)間。因此,JEP344針對(duì)這種問(wèn)題進(jìn)行了優(yōu)化。Java12 中將把 Cset拆分為強(qiáng)制及可選兩部分。有限執(zhí)行強(qiáng)制部分的CSet,執(zhí)行完成之后如果存在剩余時(shí)間,則繼續(xù)處理可選Cset部分,從而讓GC暫停時(shí)間更接近預(yù)期值。

2.2.3 G1支持NUMA技術(shù)(JEP345)

非統(tǒng)一內(nèi)存訪問(wèn)架構(gòu)(英語(yǔ):non-uniform memory access,簡(jiǎn)稱NUMA)是一種為多處理器的電腦設(shè)計(jì)的內(nèi)存架構(gòu),內(nèi)存訪問(wèn)時(shí)間取決于內(nèi)存相對(duì)于處理器的位置。在NUMA下,處理器訪問(wèn)它自己的本地內(nèi)存的速度比非本地內(nèi)存(內(nèi)存位于另一個(gè)處理器,或者是處理器之間共享的內(nèi)存)快一些。ParallelGC在前幾年已經(jīng)開(kāi)始支持NUMA技術(shù),并且對(duì)于垃圾回收器性能有較大提升。可惜的是,G1垃圾回收器在JDK14之前一直不支持此項(xiàng)技術(shù),現(xiàn)在可以通過(guò)參數(shù)+XX:+UseNUMA在使用G1垃圾回收器時(shí)使用NUMA技術(shù)。

2.3、廢棄CMS垃圾回收器

CMS垃圾回收器在JDK9徹底被廢棄,在JDK12直接被刪除。目前,G1垃圾回收器是代替CMS的最優(yōu)選擇之一。

2.4、廢棄ParallelScavenge + SerialOld 垃圾回收器組合

Java垃圾回收器有多種多樣的組合和使用方式。下面這張圖,我大概看過(guò)不差10遍,可是每次結(jié)果也是相同,記不?。。。?!

默認(rèn)垃圾回收器是哪些?
-XX:+UseParallelGC -XX:-UseParallelOldGC -XX:+UseParallelGC -XX:+UseParNewGC 這幾個(gè)參數(shù)有什么區(qū)別?
CMS垃圾回收器有哪些關(guān)鍵參數(shù)?浮動(dòng)垃圾怎么處理?如何避免Full GC產(chǎn)生?
好消息!這些以后都不用記憶了,我們只需要專注攻克三款垃圾回收器原理:默認(rèn)大哥G1、新晉新星ZGC、非親兒子Shanondoah(了解)。這里也許有人會(huì)抬杠,小內(nèi)存CMS會(huì)有更好的表現(xiàn)。ParNew仍然是高吞吐服務(wù)的首選。大道至簡(jiǎn),簡(jiǎn)單易用才是王道。G1和ZGC必定是以后JVM垃圾回收器的重點(diǎn)發(fā)展方向,與其耗費(fèi)精力記憶即將淘汰的技術(shù),不如利出一孔,精通一門!

2.4、Epsilon:低開(kāi)銷垃圾回收器

Epsilon 垃圾回收器的目標(biāo)是開(kāi)發(fā)一個(gè)控制內(nèi)存分配,但是不執(zhí)行任何實(shí)際的垃圾回收工作。下面是該垃圾回收器的幾個(gè)使用場(chǎng)景:性能測(cè)試、內(nèi)存壓力測(cè)試、極度短暫 job 任務(wù)、延遲改進(jìn)、吞吐改進(jìn)。

三、診斷和監(jiān)控相關(guān)優(yōu)化

3.1 Java Flight Recorder[JEP328]

Java Flight Recorder (JFR) 從正在運(yùn)行的 Java 應(yīng)用程序收集診斷和分析數(shù)據(jù)。 根據(jù)SPECjbb2015基準(zhǔn)壓測(cè)結(jié)果顯示,JFR 對(duì)正在運(yùn)行的 Java 應(yīng)用程序的性能影響低于1%。 對(duì)于JFR的統(tǒng)計(jì)數(shù)據(jù),可以使用 Java Mission Control (JMC) 和其他工具分析。 JFR 和 JMC 在 JDK 8 中是商業(yè)付費(fèi)功能,而在 JDK11 中都是免費(fèi)開(kāi)源的。

3.2 Java Mission Control [JMS]

Java Mission Control (JMC) 可以分析并展示 Java Flight Recorder (JFR) 收集的數(shù)據(jù),并且在 JDK 11 中是開(kāi)源的。除了有關(guān)正在運(yùn)行的應(yīng)用程序的一般信息外,JMC 還允許用戶深入了解數(shù)據(jù)。 JFR 和 JMC 可用于診斷運(yùn)行時(shí)問(wèn)題,例如內(nèi)存泄漏、GC 開(kāi)銷、熱點(diǎn)方法、線程瓶頸和阻塞 I/O。JMC可以作為現(xiàn)有JVM監(jiān)控工具的一個(gè)補(bǔ)充,做到維度更多,監(jiān)控更加實(shí)時(shí)(秒級(jí)),能從多個(gè)視角監(jiān)控當(dāng)前JVM進(jìn)程的性能,更加更快速的定位并解決問(wèn)題。

3.3 統(tǒng)一 JVM 日志(JEP158)

在以往的低版本中很難知道導(dǎo)致JVM性能問(wèn)題和導(dǎo)致JVM崩潰的根本原因。不同的JVM對(duì)日志的使用是不同的機(jī)制和規(guī)則,這就使得JVM難以進(jìn)行調(diào)試。
解決這個(gè)問(wèn)題最佳的方法:對(duì)所有的JVM組件引入一個(gè)統(tǒng)一的日志框架,這些JVM組件支持細(xì)粒度的和易配置的JVM日志。?JDK8以前常用的打印GC日志方式:

-Xloggc:/export/Logs/gc.log //輸出GC日志到指定文件
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps

3.3.1 目標(biāo):

  1. 所有日志記錄的通用命令行選項(xiàng)。

  2. 通過(guò)tag對(duì)日志進(jìn)行分類,例如:compiler, gc, classload, metaspace, svc, jfr等。一條日志可能會(huì)含有多個(gè) tag

  3. 日志包含多個(gè)日志級(jí)別:error, warning, info, debug, trace, develop。

  4. 可以將日志重定向到控制臺(tái)或者文件。

  5. error, warning級(jí)別的日志重定向到標(biāo)準(zhǔn)錯(cuò)誤stderr.

  6. 可以根據(jù)日志大小或者文件數(shù)對(duì)日志文件進(jìn)行滾動(dòng)。

  7. 一次只打印一行日志,日志之間無(wú)交叉。

  8. 日志包含裝飾器,默認(rèn)的裝飾器包括:uptime, level, tags,且裝飾可配置。

3.3.2 如何使用

-Xlog[:option]
    option         :=  [][:[][:[][:]]]
                       'help'
                       'disable'
    what           :=  [,...]
    selector       :=  [*][=]
    tag-set        :=  [+...]
                       'all'
    tag            :=  name of tag
    level          :=  trace
                       debug
                       info
                       warning
                       error
    output         :=  'stderr'
                       'stdout'
                       [file=]
    decorators     :=  [,...]
                       'none'
    decorator      :=  time
                       uptime
                       timemillis
                       uptimemillis
                       timenanos
                       uptimenanos
                       pid
                       tid
                       level
                       tags
    output-options :=  [,...]
    output-option  :=  filecount=
                       filesize=
                       parameter=value

  1. 可以通過(guò)配置-Xlog:help參數(shù),獲取常用的JVM日志配置方式。

  2. 可以通過(guò)-Xlog:disable參數(shù)關(guān)閉JVM日志。

  3. 默認(rèn)的JVM日志配置如下:

    -Xlog:all=warning:stderr:uptime,level,tags
        - 默認(rèn)配置
        - 'all' 即是包含所有tag
        - 默認(rèn)日志輸出級(jí)別warning,位置stderr
        - 包含uptime,level,tags三個(gè)裝飾
    
    
  4. 可以參考使用如下配置:

    JDK9之前參數(shù)-XX:+PrintGCDetails可參考:

    -Xlog:safepoint,classhisto*=trace,age*,gc*=info:file=/export/Logs/gc-%t.log:time,tid,level,tags:filecount=5,filesize=50MB
       - safepoint表示打印用戶線程并發(fā)及暫停執(zhí)行時(shí)間
       - classhisto表示full gc時(shí)打印堆快照信息
       - age*,gc* 表示打印包括gc及其細(xì)分過(guò)程日志,日志級(jí)別info,文件:/export/Logs/gc.log。
        - 日志格式包含裝飾符:time,tids,level,tags
        - default output of all messages at level 'warning' to 'stderr'
        will still be in effect
        - 保存日志個(gè)數(shù)5個(gè),每個(gè)日志50M大小
    
    

    查看GC前后堆、方法區(qū)可用容量變化,在JDK9之前,可以使用-XX::+PrintGeapAtGC,現(xiàn)在可參考:

    -Xlog:gc+heap=debug:file=/export/Logs/gc.log:time,tids,level,tags:filecount=5,filesize=1M
        - 打印包括gc及其細(xì)分過(guò)程日志,日志級(jí)別info,文件:/export/Logs/gc.log。
        - 日志格式包含裝飾符:time,tids,level,tags
        - default output of all messages at level 'warning' to 'stderr'
        will still be in effect
        - 保存日志個(gè)數(shù)5個(gè),每個(gè)日志1M大小
    
    

JDK9之前的GC日志:

2014-12-10T11:13:09.597+0800: 66955.317: [GC concurrent-root-region-scan-start]
2014-12-10T11:13:09.597+0800: 66955.318: Total time for which application threads were stopped: 0.0655753 seconds
2014-12-10T11:13:09.610+0800: 66955.330: Application time: 0.0127071 seconds
2014-12-10T11:13:09.614+0800: 66955.335: Total time for which application threads were stopped: 0.0043882 seconds
2014-12-10T11:13:09.625+0800: 66955.346: [GC concurrent-root-region-scan-end, 0.0281351 secs]
2014-12-10T11:13:09.625+0800: 66955.346: [GC concurrent-mark-start]
2014-12-10T11:13:09.645+0800: 66955.365: Application time: 0.0306801 seconds
2014-12-10T11:13:09.651+0800: 66955.371: Total time for which application threads were stopped: 0.0061326 seconds
2014-12-10T11:13:10.212+0800: 66955.933: [GC concurrent-mark-end, 0.5871129 secs]
2014-12-10T11:13:10.212+0800: 66955.933: Application time: 0.5613792 seconds
2014-12-10T11:13:10.215+0800: 66955.935: [GC remark 66955.936: [GC ref-proc, 0.0235275 secs], 0.0320865 secs]

JDK9統(tǒng)一日志框架輸出的日志格式 :

[2021-02-09T21:12:50.870+0800][258][info][gc] Using G1
[2021-02-09T21:12:51.751+0800][365][info][gc] GC(0) Pause Young (Concurrent Start) (Metadata GC Threshold) 60M->5M(4096M) 7.689ms
[2021-02-09T21:12:51.751+0800][283][info][gc] GC(1) Concurrent Cycle
[2021-02-09T21:12:51.755+0800][365][info][gc] GC(1) Pause Remark 13M->13M(4096M) 0.959ms
[2021-02-09T21:12:51.756+0800][365][info][gc] GC(1) Pause Cleanup 13M->13M(4096M) 0.127ms
[2021-02-09T21:12:51.758+0800][283][info][gc] GC(1) Concurrent Cycle 7.208ms
[2021-02-09T21:12:53.232+0800][365][info][gc] GC(2) Pause Young (Normal) (G1 Evacuation Pause) 197M->15M(4096M) 17.975ms
[2021-02-09T21:12:53.952+0800][365][info][gc] GC(3) Pause Young (Concurrent Start) (GCLocker Initiated GC) 114M->17M(4096M) 15.383ms
[2021-02-09T21:12:53.952+0800][283][info][gc] GC(4) Concurrent Cycle

四、更加優(yōu)雅的語(yǔ)法或者方法

4.1、集合工廠方法

List,Set 和 Map 接口中,新的靜態(tài)工廠方法可以創(chuàng)建不可變集合

// 創(chuàng)建只有一個(gè)值的可讀list,底層不使用數(shù)組
static <E> List<E> of(E e1) {
   return new ImmutableCollections.List12<>(e1);
}
// 創(chuàng)建有多個(gè)值的可讀list,底層使用數(shù)組
static <E> List<E> of(E e1, E e2, E e3) {
   return new ImmutableCollections.List12<>(e1, e2,e3);
}
// 創(chuàng)建單例長(zhǎng)度為0的Set結(jié)合
static <E> Set<E> of() {
   return ImmutableCollections.emptySet();
}
static <E> Set<E> of(E e1) {
   return new ImmutableCollections.Set12<>(e1);
}

4.2、接口私有方法

Java 8, 接口可以有默認(rèn)方法。Java9之后,可以在接口內(nèi)實(shí)現(xiàn)私有方法實(shí)現(xiàn)。

public interface HelloService {
    public void sayHello();
    // 默認(rèn)方法
    default void saySomething(){
        syaEngHello();
        sayHello();
    };
    // 私有方法
    private void syaEngHello(){
        System.out.println("Hello!");
    }
}

4.3、改進(jìn)的 Stream API

Java 9 為 Stream 新增了幾個(gè)方法:dropWhile、takeWhile、ofNullable,為 iterate 方法新增了一個(gè)重載方法。

// 循環(huán)直到第一個(gè)滿足條件后停止
default Stream takeWhile(Predicate predicate);
// 循環(huán)直到第一個(gè)滿足條件后開(kāi)始
default Stream dropWhile(Predicate predicate);
// 根據(jù)表達(dá)式生成迭代器
static  Stream iterate(T seed, Predicate hasNext, UnaryOperator next);
// 使用空值創(chuàng)建空的Stream,避免空指針
static  Stream ofNullable(T t);

4.4、JShell

JShell 是 Java 9 新增的一個(gè)交互式的編程環(huán)境工具。它允許你無(wú)需使用類或者方法包裝來(lái)執(zhí)行 Java 語(yǔ)句。它與 Python 的解釋器類似,可以直接 輸入表達(dá)式并查看其執(zhí)行結(jié)果。

4.5、局部類型推斷(JEP286)

JDK10推出了局部類型推斷功能,可以使用var作為局部變量類型推斷標(biāo)識(shí)符,減少模板代碼的生成 ,本質(zhì)還是一顆語(yǔ)法糖。同時(shí)var關(guān)鍵字的用于與lombok提供的局部類型推斷功能也基本相同。

public static void main(String[] args) throws Exception {
    var lists = List.of("a", "b", "c");
    for (var word : lists) {
        System.out.println(word);
    }
}

? var關(guān)鍵字只能用于可推斷類型的代碼位置,不能使用于方法形式參數(shù),構(gòu)造函數(shù)形式參數(shù),方法返回類型等。標(biāo)識(shí)符var不是關(guān)鍵字,它是一個(gè)保留的類型名稱。這意味著var用作變量,方法名或則包名稱的代碼不會(huì)受到影響。但var不能作為類或則接口的名字。

? var關(guān)鍵字的使用確實(shí)可以減少很多沒(méi)必要的代碼生成。但是,也存在自己的缺點(diǎn):1. 現(xiàn)在很多IDE都存在自動(dòng)代碼生成的快捷方式,所以使不使用var關(guān)鍵字區(qū)別不大。2. 局部類型推斷,不光是編譯器在編譯時(shí)期要推斷,后面維護(hù)代碼的人也要推斷,會(huì)在一定程度上增加理解成本。

4.6、標(biāo)準(zhǔn)Java HTTP Client

使用過(guò)Python或者其他語(yǔ)言的HTTP訪問(wèn)工具的人,都知道JDK提供的HttpURLConnection或者Apache提供的HttpClient有多么的臃腫。簡(jiǎn)單對(duì)比一下。

python 自帶的urllib工具:

response=urllib.request.urlopen('https://www.python.org')  #請(qǐng)求站點(diǎn)獲得一個(gè)HTTPResponse對(duì)象
print(response.read().decode('utf-8'))   #返回網(wǎng)頁(yè)內(nèi)容

JDK:

HttpURLConnection connection = (HttpURLConnection) new URL("http://localhost:8080/demo/list?name=HTTP").openConnection();
connection.setRequestMethod("GET");
connection.connect();
int responseCode = connection.getResponseCode();
log.info("response code : {}", responseCode);
// read response
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
} finally {
    connection.disconnect();
}

Apache HttpClient:

CloseableHttpClient httpClient = HttpClientBuilder.create().build();
// 創(chuàng)建Get請(qǐng)求
HttpGet httpGet = new HttpGet("http://localhost:12345/doGetControllerOne");
// 響應(yīng)模型
CloseableHttpResponse response = null;
// 由客戶端執(zhí)行(發(fā)送)Get請(qǐng)求
response = httpClient.execute(httpGet);
// 從響應(yīng)模型中獲取響應(yīng)實(shí)體
HttpEntity responseEntity = response.getEntity();
System.out.println("響應(yīng)狀態(tài)為:" + response.getStatusLine());

Java 9 中引入了標(biāo)準(zhǔn)Http Client API 。并在 Java 10 中進(jìn)行了更新的。 到了Java11,在前兩個(gè)版本中進(jìn)行孵化的同時(shí),Http Client 幾乎被完全重寫,并且現(xiàn)在完全支持異步非阻塞。與此同時(shí)它是 Java 在 Reactive-Stream 方面的第一個(gè)生產(chǎn)實(shí)踐,其中廣泛使用了 Java Flow API。

HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
      .uri(URI.create("http://openjdk.java.net/"))
      .build();
client.sendAsync(request, BodyHandlers.ofString())
      .thenApply(HttpResponse::body)
      .thenAccept(System.out::println)
      .join();

4.7、Helpful NullPointerExceptions(JEP358)

隨著流式編程風(fēng)格的流行,空指針異常成為了一種比較難定位的BUG。例如:

a.b.c.i = 99;
a[i][j][k] = 99;

在之前,我們只能收到以下異常堆棧信息,然后必須借助DEBUG工具調(diào)查問(wèn)題:

Exception in thread "main" java.lang.NullPointerException
    at Prog.main(Prog.java:5)

優(yōu)化后,我們可以得到更加優(yōu)雅的空指針異常提示信息:

Exception in thread "main" java.lang.NullPointerException: 
        Cannot read field "c" because "a.b" is null
    at Prog.main(Prog.java:5)
    
Exception in thread "main" java.lang.NullPointerException:
        Cannot load from object array because "a[i][j]" is null
    at Prog.main(Prog.java:5)


4.8、更加優(yōu)雅的instance of 語(yǔ)法(JEP394)

以下代碼是每個(gè)Java開(kāi)發(fā)工程師的一塊心?。?/p>

if (obj instanceof String) {
    String s = (String) obj;    // grr...
    ...
}

上面的instanc of語(yǔ)法一共做了三件事:

  1. 判斷是否為String類型;

  2. 如果是,轉(zhuǎn)成String類型;

  3. 創(chuàng)建一個(gè)名為s的臨時(shí)變量;
    在JDK16中,使用模式匹配思想改進(jìn)了instance of 用法,可以做到以下優(yōu)化效果:

if (obj instanceof String s) {// obj是否為String類型,如果是創(chuàng)建臨時(shí)變量s
    // Let pattern matching do the work!
    ...
}

我們可以看到,整體代碼風(fēng)格確實(shí)優(yōu)雅了很多。變量s的作用域?yàn)闈M足條件的判斷條件范圍之內(nèi)。因此,以下使用也是合法的:

if (obj instanceof String s && s.length() > 5) {// 因?yàn)?amp;&具有短路功能
    flag = s.contains("jdk");
}

但是以下用法,則會(huì)報(bào)錯(cuò):

if (obj instanceof String s || s.length() > 5) {    // Error!
    ...
}

合理使用,則可以達(dá)到以下效果:

// 優(yōu)化使用前
public final boolean equals(Object o) {
    if (!(o instanceof Point))
        return false;
    Point other = (Point) o;
    return x == other.x
        && y == other.y;
}
// 優(yōu)化使用后:
public final boolean equals(Object o) {
    return (o instanceof Point other)
        && x == other.x
        && y == other.y;
}

4.9、更加優(yōu)雅的Switch用法

Java里有一句名言:可以用switch結(jié)構(gòu)實(shí)現(xiàn)的程序都可以使用if語(yǔ)句來(lái)實(shí)現(xiàn)。而且Swtich語(yǔ)法在某些工程師眼里,根本沒(méi)有if語(yǔ)句簡(jiǎn)潔。JDK14中提供了更加優(yōu)雅的swtich語(yǔ)法,例如:

// 之前
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 (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);
}

還可以把switch語(yǔ)句當(dāng)成一個(gè)表達(dá)式來(lái)處理:

T result = switch (arg) {
    case L1 -> e1;
    case L2 -> e2;
    default -> e3;
};

static void howMany(int k) {
    System.out.println(
        switch (k) {
            case  1 -> "one";
            case  2 -> "two";
            default -> "many";
        }
    );
}

還可以配合關(guān)鍵字yield,在復(fù)雜處理場(chǎng)景里,返回指定值:

int j = switch (day) {
    case MONDAY  -> 0;
    case TUESDAY -> 1;
    default      -> {
        int k = day.toString().length();
        int result = f(k);
        yield result;
    }
};

還有嗎?其實(shí)在JDK17中,還提出了Swtich 模式匹配的預(yù)覽功能,可以做到更優(yōu)雅的條件判斷:

// 優(yōu)化前
static String formatter(Object o) {
    String formatted = "unknown";
    if (o instanceof Integer i) {
        formatted = String.format("int %d", i);
    } else if (o instanceof Long l) {
        formatted = String.format("long %d", l);
    } else if (o instanceof Double d) {
        formatted = String.format("double %f", d);
    } else if (o instanceof String s) {
        formatted = String.format("String %s", s);
    }
    return formatted;
}
// 優(yōu)化后
static String formatterPatternSwitch(Object o) {
    return switch (o) {
        case Integer i -> String.format("int %d", i);
        case Long l    -> String.format("long %d", l);
        case Double d  -> String.format("double %f", d);
        case String s  -> String.format("String %s", s);
        default        -> o.toString();
    };
}

五、字符串壓縮-Compact Strings(JEP254)

字符串是我們?nèi)粘>幊讨惺褂米铑l繁的基本數(shù)據(jù)類型之一。目前,字符串類底層都使用了一個(gè)字符數(shù)組來(lái)實(shí)現(xiàn),每個(gè)字符使用2個(gè)字節(jié)(16位)空間。實(shí)際上,大量的字符都屬于Latin-1字符范圍內(nèi),我們只需要一個(gè)字節(jié)就能存儲(chǔ)這些數(shù)據(jù),因此這里有巨大的可壓縮空間;SPECjbb2005壓測(cè)結(jié)果顯示對(duì)于GC時(shí)間及GC時(shí)間間隔都有一定程度的提升。詳細(xì)原理文檔也可以參考【Oracle對(duì)CompackStrings分享】

六、 Java Flow API

Reactive Streams是一套非阻塞背壓的異步數(shù)據(jù)流處理規(guī)范。從Java9開(kāi)始,Java原生支持Reactive Streams編程規(guī)范。Java Flow API是對(duì)Reactive Streams編程規(guī)范的1比1復(fù)刻,同時(shí)意味著從Java9開(kāi)始,JDK本身開(kāi)始在Reactive Streams方向上進(jìn)行逐步改造。

七、新一代JIT編譯器 Graal

即時(shí)編譯器在提高JVM性能上扮演著非常重要的角色。目前存在兩JIT編譯器:編譯速度較快但對(duì)編譯后的代碼優(yōu)化較低的C1編譯器;編譯速度較慢但編譯后的代碼優(yōu)化較高的C2編譯器。兩個(gè)編譯器在服務(wù)端程序及分層編譯算法中扮演著非常重要的角色。但是,C2編譯器已經(jīng)存在將近20年了,其中混亂的代碼以及部分糟糕的架構(gòu)使其難以維護(hù)。JDK10推出了新一代JIT編譯器Graal(JEP317)。Graal作為C2的繼任者出現(xiàn),完全基于Java實(shí)現(xiàn)。Graal編譯器借鑒了C2編譯器優(yōu)秀的思想同時(shí),使用了新的架構(gòu)。這讓Graal在性能上很快追平了C2,并且在某些特殊的場(chǎng)景下還有更優(yōu)秀的表現(xiàn)。遺憾的是,Graal編譯器在JDK10中被引入,但是在JDK17(JEP410)中被廢除了,理由是開(kāi)發(fā)者對(duì)其使用較少切維護(hù)成本太高。開(kāi)發(fā)者也可以通過(guò)使用GraalVM來(lái)使用Graal編譯器;

總結(jié)

本文介紹了JDK9-JDK17升級(jí)過(guò)的近200個(gè)JEP中作者狹隘角度認(rèn)為價(jià)值較高的功能做了一個(gè)綜述類介紹。主要目的有兩個(gè):

  1. 通過(guò)本文,大家可以對(duì)即將使用的JDK11及JDK17新特性有一個(gè)籠統(tǒng)的了解,希望可以看到一些Java預(yù)發(fā)最近幾年的發(fā)展方向。

  2. 通過(guò)本文也可以看出,從JDK9到JDK17,Java生態(tài)還是生機(jī)勃勃。大量功能的更新意味著更優(yōu)秀的性能及更高效的開(kāi)發(fā)效率,積極主動(dòng)的嘗試高版本JDK;
    當(dāng)然,JDK8到JDK17還有需求優(yōu)秀的新特性,例如:shanondoah垃圾回收器、Sealed Classes、Records;
    鑒于本人能力有限,文中會(huì)出現(xiàn)一些漏洞,希望大家找出并指正,讓本文成長(zhǎng)為后續(xù)JDK17升級(jí)的掃盲手冊(cè);文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-417259.html

到了這里,關(guān)于JDK8到JDK17有哪些吸引人的新特性?的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • JDK8、JDK11、JDK17和JDK21這幾個(gè)版本更新的主要特性

    JDK8、JDK11、JDK17和JDK21這幾個(gè)版本更新的主要特性

    JDK8 是 Java 的一個(gè)重大更新版本,引入了一系列新特性和改進(jìn),主要包括: Lambda 表達(dá)式: Lambda 表達(dá)式允許我們以簡(jiǎn)潔、函數(shù)式的方式編寫代碼,使代碼更易于理解和維護(hù)。- Stream API : Stream API 提供了一套聲明式處理數(shù)據(jù)的方式,使得對(duì)集合和數(shù)組的操作更加直觀和高效。

    2024年04月29日
    瀏覽(23)
  • JDK17新特性之--JDK9到JDK17 String 新增的新方法

    JDK17新特性之--JDK9到JDK17 String 新增的新方法

    JDK9之后對(duì)String底層存儲(chǔ)數(shù)據(jù)結(jié)構(gòu)進(jìn)行了重大的修改 1 ,同步也增加了許多新的方法,主要有Text Blocks、chars()、codePoints()、describeConstable()、formatted()、indent()、isBlank()、isEmpty()、lines()、repeat()、strip()、stripLeading()、stripIndent()、stripTrailing()、translateEscapes(),接下來(lái)就逐一看看每個(gè)

    2024年02月04日
    瀏覽(23)
  • JDK8新特性

    是 Java 8 引入的一種處理集合數(shù)據(jù)的新方式。它提供了一種更簡(jiǎn)潔、更易讀和更靈活的方式來(lái)操作和處理集合數(shù)據(jù)。流的核心思想是將數(shù)據(jù)處理操作集中在一起,可以進(jìn)行過(guò)濾、映射、排序、聚合等一系列操作,而不需要顯式地使用循環(huán)和條件語(yǔ)句。 以下是流(Stream)API 的一

    2024年02月15日
    瀏覽(20)
  • JDK8新特性-上部

    JDK8新特性-上部

    ??博客x主頁(yè):己不由心王道長(zhǎng)??! ??文章說(shuō)明:JDK8新特性?? ?系列專欄:Java基礎(chǔ) ??本篇內(nèi)容:對(duì)JDK8的新特性進(jìn)行學(xué)習(xí)和講解?? ??每日一語(yǔ):這個(gè)世界本來(lái)就不完美,如果我們?cè)俨唤邮懿煌昝赖淖约?,那我們要怎么活?? ?? 交流社區(qū): 己不由心王道長(zhǎng)(優(yōu)質(zhì)編程

    2024年02月11日
    瀏覽(22)
  • Mac卸載jdk8,安裝jdk17

    Mac卸載jdk8,安裝jdk17

    本次操作基于MacBook 因?yàn)楣ぷ餍枰枰獙dk版本由jdk8升級(jí)到j(luò)dk17,同一臺(tái)機(jī)器上是可以同時(shí)安裝多個(gè)版本的jdk的,但是為了避免一些沖突和未知問(wèn)題,這里直接卸載舊版本jdk,然后再重新安裝新版本。 先查看本機(jī)安裝的jdk: 刪除java運(yùn)行環(huán)境: 到j(luò)ava的目錄,用ls命令查看機(jī)

    2024年02月08日
    瀏覽(27)
  • JDK8-JDK17版本升級(jí)

    JDK8-JDK17版本升級(jí)

    記錄Records是添加到 Java 14 的一項(xiàng)新功能。它允許你創(chuàng)建用于存儲(chǔ)數(shù)據(jù)的類。它類似于 POJO 類,但代碼少得多;大多數(shù)開(kāi)發(fā)人員使用 Lombok 生成 POJO 類,但是有了記錄,你就不需要使用任何第三方庫(kù)。 sealed將類的繼承限制為一組有限的子類 密封類的子類可以聲明為fina

    2024年01月17日
    瀏覽(18)
  • JDK8新特性之方法引用【 ::】

    JDK8新特性之方法引用【 ::】

    接下來(lái)看看由輝輝所寫的關(guān)于方法引用的相關(guān)操作吧 目錄 ????Welcome Huihui\\\'s Code World ! !???? 一.是什么 二.為什么要用 三.什么時(shí)候用 四.怎么用 常見(jiàn)的引用方式 ?符號(hào)表示: “ ::” 是一種引用運(yùn)算符,它所在的表達(dá)式稱為方法引用? 1.簡(jiǎn)化代碼 方法引用可以將復(fù)雜的代

    2024年02月11日
    瀏覽(47)
  • java jdk8和jdk17同時(shí)存在【環(huán)境配置】

    java jdk8和jdk17同時(shí)存在【環(huán)境配置】

    jdk8:https://www.oracle.com/cn/java/technologies/javase/javase8u211-later-archive-downloads.html jdk17:https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html PS:jdk8在下載結(jié)束,安裝的時(shí)候,需要有兩個(gè)文件分別是jre和jdk JRE: 是Java Runtime Environment,是java程序的運(yùn)行環(huán)境。既然是運(yùn)行,當(dāng)然要包含

    2024年02月07日
    瀏覽(31)
  • JDK8升級(jí)JDK17過(guò)程中遇到的那些坑

    JDK8雖然非常好,但是JDK版本已經(jīng)發(fā)布到JDK20了,且JDK8后的版本升級(jí)了很多新的特性,如模塊化、ZGC以及虛擬線程、結(jié)構(gòu)性并發(fā)等,也是非常有吸引力的,所以決定將基于JDK8的項(xiàng)目升級(jí)到最近的LTS版本JDK17。 下載JDK17的最新版本 jdk-17_linux-x64_bin.tar.gz ,解壓縮后移動(dòng)到 /usr/lib

    2024年02月11日
    瀏覽(17)
  • JDK8和JDK17安裝切換,IDEA配置多個(gè)版本JDK

    JDK8和JDK17安裝切換,IDEA配置多個(gè)版本JDK

    JAVA之父高斯林推薦我們用JDK17,請(qǐng)盡快離開(kāi)JDK8。JDK17 LTS在每個(gè)維度上都是一個(gè)巨大的飛躍: 在Java 17正式發(fā)布之前,Java開(kāi)發(fā)框架Spring率先在官博宣布,Spring Framework 6和Spring Boot 3計(jì)劃在2022年第四季度實(shí)現(xiàn)總體可用性的高端基線: Java 17+(來(lái)自 Spring Framework 5.3.x 線中的 Java 8-17)

    2023年04月27日
    瀏覽(27)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包