JDK8升級JDK11最全實踐乾貨來了

来源:https://www.cnblogs.com/jingdongkeji/archive/2023/09/19/17713981.html
-Advertisement-
Play Games

截至目前(2023年),Java8發佈至今已有9年,2018年9月25日,Oracle發佈了Java11,這是Java8之後的首個LTS版本。那麼從JDK8到JDK11,到底帶來了哪些特性呢?值得我們升級嗎?而且升級過程會遇到哪些問題呢?帶著這些問題,本篇文章將帶來完整的JDK8升級JDK11最全實... ...


1、前言

截至目前(2023年),Java8發佈至今已有9年,2018年9月25日,Oracle發佈了Java11,這是Java8之後的首個LTS版本。那麼從JDK8到JDK11,到底帶來了哪些特性呢?值得我們升級嗎?而且升級過程會遇到哪些問題呢?帶著這些問題,本篇文章將帶來完整的JDK8升級JDK11最全實踐。

2、為什麼升級JDK11

1)性能提升

更好的垃圾收機制、更快的類載入器, 加快應用程式的運行速度。綜合評估,從Java 8 升級到 Java 11,G1GC平均速度提升16.1%,ParallelGC為4.5%基於OptaPlanner的用例基準測試表明)

2)特性和改進

局部變類型推斷、新的 API、HTTP/2客戶端、Lambda表達式的新特性等,這些新特性可以提高開發效率。

3)支持最新的技術和框架

許多新的技術和框架已經或即將開始依賴於JDK11或以上版本,升級後可以保證應用程式能夠分利用這些新的技術和框架。

4)長期支持版本

JDK11是Oracle官方發佈的一個長期支持(LTS),意味著它將獲得長期的更新和支持,有助於保持用程式的穩定性和可靠性。

5)行業趨勢

數據來自 New Relic 在2023年1月發佈的Java生態報告,從下圖可以看出:

  • 目前市面上有 超過 56%的應用程式使用了JDK 11,Java 8 的使用從2020年的84%降低到了現在的32%左右。大部分公司在這三年之間都升級到了JDK 11 或者 JDK 17這兩個LTS版本上面。
  • 垃圾收集器使用情況來看,JDK11版本及以上 G1使用率最高,占比高達65%

3、升級後GC效果

先給出結論:

  1. JDK11相對於JDK8,所有垃圾回收器的性能都有提升,特別是大記憶體機器下G1的提升最明顯
  2. 8G記憶體以下的機器,推薦使用Parallel GC,如果特別追求低延遲,選擇犧牲吞吐量,可以使用G1,並設置期望的最大垃圾回收停頓時間來控制
  3. 8G及以上的大記憶體機器,推薦使用G1 4、不推薦使用CMS,升級後從各項數據來看,CMS收集器都不如G1

我在JDOS平臺上選擇了不同配置的機器(2C4G、4C8G、8C16G),並分別使用JDK8和JDK11進行部署和壓測。

整個壓測過程限時60分鐘,用180個虛擬用戶併發請求一個介面,每次介面請求都創建512Kb的數據。最終產出不同GC回收器的各項指標數據,來分析GC的性能提升效果。

以下是壓測的性能情況:

* 上面給出的GC升級效果,採用的是預設的配置,沒有做任何優化,只提供參考。真正的GC調優是個技術活,需要根據業務需求、機器配置和實際壓測效果等綜合評估來選出最合適的GC垃圾回收器。

* 不同垃圾回收器的特點:

  1. Parallel GC - JDK 8及以下版本的預設收集器,關註吞吐量,嘗試在最小延遲的情況下儘快完成工作並提高吞吐量。

  2. CMS - 一個老年代收集器,基於標記-清除演算法實現,關註延遲,以最短回收停頓時間為目標

  3. Garbage First(G1)- JDK 9以後的預設收集器,G1 關註總體的性能,會嘗試在吞吐量和延遲之間做平衡。

4、JDK11帶來了哪些新特性

4.1、GC改進

預設垃圾回收器改為G1,廢棄CMS垃圾回收器

◦ G1特點:目標是降低應用程式的停頓時間並提高吞吐量。

引入ZGC垃圾回收器(可伸縮低延遲垃圾收集器) 但由於JDK11中ZGC還不夠完善,推薦在JDK17中再使用穩定版ZGC

◦ Full GC的停頓不超過10毫秒

◦ 支持TB級堆記憶體回收

◦ 相對於G1吞吐量下降不超過15%

4.2、模塊化

Java9引入了對於模塊化軟體支持,而Java11進一步擴展了這種特性。模塊化讓應用程式 更精簡,減少對其他類庫的依賴和冗餘代碼,提高運行效率和安全性

然而,目前不推薦使用模塊化,因為相關組件生態還不完善,並且模塊化帶來的價值不夠突出。具體原因請看後面章節的詳細分析:新特性實踐-模塊化。

4.3、語法增強

◦ 局部變數推斷,引入var局部變數類型,允許開發人員省略通常不必要的局部變數類型初始化聲明

◦ Lambda表達式簡化,內部可以使用var

介面中可以定義私有方法,可以實現介面方法的訪問控制和代碼復用

4.4、API增強

HTTPClient標準化支持:強大而靈活的HTTP客戶端API,支持多協議(HTTP/2、WebSocket)、非同步非阻塞、流操作和連接池等特性。ps:再也不需要用第三包 HttpClient 工具包

字元串方法增強isBlanklinesstripstripLeadingstripTrailingrepeat

Files增強:readString、WriteString

InputStream增強:transferTo(流快速拷貝)

stream增強,dropWhile(從集合中刪除滿足的)、takeWhile(從集合中獲取滿足的)、ofNullable

集合工廠方法:Sets.of()、List.of()、Map.of()、Map.ofEntries(),舉例:List list = List.of("Java", "Python", "C++");

5、如何升級

5.1、升級應用評估

  • 為保證穩定性,我們優先在新業務新應用來落地實施JDK11的升級。

5.2、JDK選擇

自從2019年1月起,Oracle JDK後續的版本開始商用收費,所以推薦大家選擇OpenJDK11,OpenJDK和OracleJDK功能上沒有差異,支持免費商用。

OpenJDK11下載地址:https://jdk.java.net/archive/

5.3、GC配置

根據自身需求和機器配置選擇GC,不同GC的JVM啟動參數配置:

  • G1垃圾回收器(JDK11預設,不需要手動配置):-XX:+UseG1GC
  • Parallel GC垃圾回收器:XX:+UseParallelGC

5.4、升級過程踩坑

整個升級過程還是比較簡單的,除了升級JDK版本,實際遇到的問題如下:

5.5、升級後驗證

升級後完成,做好單測和回歸測試,推薦能做個壓測驗證,防止影響線上服務穩定性

6、新特性實踐-模塊化

Java一直是構建大型應用程式的主流語言之一。然而隨著Java生態系統中存在著大量庫和複雜的代碼塊之間關係難以理清的問題,構建系統變得困難且超出了我們的理解和有效開發的範圍。特別是在使用繁多的Java存檔文件(Java Archive, JAR)時,這一問題變得更加突出。為了應對這種複雜性,模塊化能夠很好地管理和減少代碼的複雜性。因此自Java9開始,引入了模塊化系統。通過模塊化,Java本身也得以進行模塊化改進。

6.1、模塊化是什麼?

模塊化指的是JAVA平臺的模塊系統(Java Platform Module System),簡稱JPMS。JPMS引入一種新方式來組織和構建Java應用程式,它將代碼分為相互獨立、可復用的模塊。每個塊都有自己的命名空間,明確聲明並控制其他模塊的訪問許可權。這種模塊化設計使得開發人員能夠更好地維護複雜的應用程式,提高代碼的復用性、可維護性和安全性,同時提升應用的載入速度和性能。****最大的特點是可以定義模塊描述符來隔離module(Jar包)內部類的訪問許可權。

模塊化的幾點關鍵說明:

1)相對於JDK8的變動

  • JDK9以後引入了一個新組件module:模塊描述符module-info.java,用於將一組相關的包放入一個組中。
  • 在Java8和更早的應用程式中,應用程式將包作為頂級組件,Java9以後應用程式將模塊作為頂級組件
  • 一個模塊(Jar包)只能有一個module-info.java。

2)和maven的關係

模塊化並不是要替代maven,和maven本身並不衝突,maven定義jar之間的依賴關係,模塊化是對已經依賴的jar下的包進行更細粒度依賴控制

3)如何相容舊應用

天然相容舊應用。為了向後相容舊項目,一些庫本身並未模塊化,其仍然可以作為模塊在模塊路徑中使用,而這些庫在模塊路徑上時會被轉化為自動模塊,例如:jackson-databind-1.0.0.jar將成為自動模塊jackson.databind

6.2、帶來了哪些好處?

1)封裝和隔離,更好的訪問控制

模塊化允許開發者將代碼和資源封裝在獨立的模塊中。模塊之間可以明確地定義公開和私有的API,提供了更好的代碼隔離性和可維護性。

ps:新業務單應用可以按照領域模型來進行多模塊的劃分,以避免代碼腐化。簡單舉例單應用下存在產品.jar、訂單.jar。訂單依賴產品,通過模塊化的限制,訂單隻能使用產品中明確對外暴露的類,這樣就避免傳統模式訂單.jar可能依賴了產品.jar中普通的類導致代碼腐化的問題,也降低後續領域服務拆分的複雜度

2)更好的可伸縮性,載入速度的提升

模塊化系統使得Java平臺更加可伸縮,通過模塊化定義,可以僅載入需要的模塊,從而提升載入類的效率,最終減少了應用程式的記憶體占用和啟動時間,同時打包後的程式也更小。

3)明確的依賴關係

模塊化系統要求在模塊之間明確定義依賴關係。在編譯或運行代碼之前,模塊系統會檢查模塊是否滿足所有依賴關係,從而導致更少的運行時錯誤。

4)安全

在JVM的最深層次上執行強封裝,減少Java運行時的攻擊面,同時無法獲得對敏感內部類的反射訪問。

6.3、如何使用

1)定義module-a.jar

包結構如下:

com.jdt.a
        person
            Men.java
        reflect
            ReflectModel.java
        module-info.java    




module-info文件內容如下:

module module.a { 
    //指令用於指定一個模塊中哪些包下的public對外是可訪問的,包括直接引入和反射使用 
    exports com.jdt.a.person; 
    // 只能被反射調用,用於指定某個包下所有的 public 類都只能在運行時可被別的模塊進行反射,並且該包下的所有的類及其乘員都可以通過反射進行訪問。 
    opens com.jdt.a.refect; 
}




2)定義module-b.jar,包的pom中指定依賴了module-a

包結構如下:

com.jdt.b
        test
            Test.java
        module-info.java    




module-info文件內容如下:

module module.b {
     //依賴a下的包
     requires module.a;
}




3)此時module-b.jar,在編寫編碼時,會遇到如下問題

6.4、實踐過程的坑

上面簡單介紹了模塊化的知識,具體在落地過程中,我們主要踩了以下的坑,供大家參考

1)依賴JSF包時無法模塊化

* JSF是京東內部使用的高性能RPC框架

進行模塊化時,pom中依賴了jsf包,模塊定義如下:

module module.a {
    requires  fastjson;
    //依賴jsf包名
    requires  jsf.lite;

    exports com.jd.jdk.test.module;
}




此時編譯報錯如下:提示找不到模塊:jsf.lite,但是pom中明明指定依賴了jsf.lite

問題原因:

經過一系列定位研究,發現jsf-lite包中,/META-INF/services下的文件org.glassfish.jersey.internal.spi.AutoDiscoverable裡面寫的類是com.alibaba.fastjson.support.jaxrs.FastJsonAutoDiscoverable,此類並未在當前jsf.lite包中定義,屬於com.alibaba.fastjson包的。

但是我們的pom中明明也依賴了com.alibaba.fastjson包,為什麼模塊化後,就找不到了呢?

主要原因在於模塊化遇到SPI(Service Provider Interface)時的約束:模塊化時,SPI機制要求配置中定義依賴的類必須本模塊定義的,不能是其他模塊的包(來自它不擁有的包),否則,此包將無法被模塊化

這樣也就解釋了,為什麼上面jsf無法找到module的問題,jsf-lite裡面設置了它不擁有的包:com.alibaba.fastjson.support.jaxrs.FastJsonAutoDiscoverable,導致jsf-lite包無法被自動模塊化

解決方案:

1、聯繫JSF團隊,升級JSF包,修複上面說的FastJsonAutoDiscoverable配置錯誤的問題。

2)拆包問題(模塊隔離)

模塊化約束:jdk9以上,使用模塊化時不支持拆分包的形式依賴

拆分包意味著兩個模塊包含相同的包,Java模塊系統不允許拆分包。拆分包始終是不正常的,而當使用解析可傳遞依賴項的構建工具(如Maven等)時,很容易出現同一個庫的多個版本,當Java模塊系統檢測到一個包存在於模塊路徑上的多個模塊中時,就會拒絕啟動。

例如:

module-a.jar包結構定義:
com.foo.package
    A.java
    
module-b.jar包結構定義:
com.foo.package
    B.java   




當module-c同時依賴module-a和module-b時,如上編譯時會報一個錯,Package com.foo.package in both module module.b and module module.a,這就是JAVA9的模塊隔離,要求只能從一個模塊(module)中讀取同一個包(package),不能跨模塊讀取。

解決方案:

如果在使用模塊化時,遇到了拆分包問題,無論如何都是無法繞過的。即使從用戶角度來看基於類路徑的應用程式可以正確工作,你也最終需要處理這些問題。此時只能停用模塊化或升級jar包,避免拆分包問題

6.5、模塊化落地總結

目前不推薦使用模塊化,因為相關組件生態還不完善,並且模塊化帶來的價值不夠突出:

  1. 很多中間件都是基於jdk8構建的,都有可能遇到模塊化相容的問題,比如:jsf,需要jsf強制升級才可以使用模塊化

  2. 拆包問題無法解決,比如:aws-java-sdk-s3、fluent等。

7、總結

  1. 升級過程簡單,升級後可以使用更多新特性和更好的GC性能,所以 建議升級到JDK11
  2. 現階段 不推薦使用模塊化,但是不用擔心會影響JDK11的升級。

另外聽說JDK17的 ZGC可以達到亞秒級停頓,但考慮到JDK11的ZGC還不是很穩定,所以本次不做測試,後面升級到JDK17後再給大家分享ZGC壓測效果。

希望以上分享可以給大家帶來實際的幫助。

作者:京東科技 曲振富

來源:京東雲開發者社區 轉載請註明來源


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 01、背景 工作中遇到項目使用Disruptor做消息隊列,對你沒看錯,不是Kafka,也不是rabbitmq;Disruptor有個最大的優點就是快,還有一點它是開源的哦,下麵做個簡單的記錄. 02、Disruptor介紹 Disruptor 是英國外匯交易公司LMAX開發的一個高性能隊列,研發的 ...
  • Redis到底是多線程還是單線程 Redis 6.0版本之前的單線程指的是其網路I/O和鍵值對的讀寫是由一個線程完成的。 多線程在Redis 6.0中的引入是為了改善一些特定場景下的性能問題,特別是在大型多核系統上。Redis 6.0引入了多個I/O線程,這些線程負責處理網路事件的監聽和接收。主線程 ...
  • 基於java圖書商城管理系統設計與實現,網上圖書商城的管理系統,網上商城,線上圖書信息管理系統,上線圖書商城,網上圖書商城,圖書借閱管理系統。 ...
  • 問題回溯 2023年Q2某日運營反饋一個問題,商品系統商家中心某批量工具模板無法下載,導致功能無法使用(因為模板是動態變化的) 商家中心報錯(JSON串): {"code":-1,"msg":"失敗"} 負責的同事看到失敗後立即與我展開討論(因為不是關鍵業務,所以不需要回滾,修複即可),我們發現新功 ...
  • OpenHarmony Meetup 常州站正火熱招募中! 誠邀充滿激情的開發者參與線下盛會~ 探索OpenHarmony前沿科技,暢談未來前景, 感受OpenHarmony生態構建之路的魅力! 線下參與,名額有限,僅限20位幸運者! 報名截止時間為9月26日24:00點,快快行動起來~ 參加Ope ...
  • 一. gcc 安裝 yum install gcc-c++ 安裝 nginx 需要先將官網下載的源碼進行編譯,編譯依賴 gcc 環境,如果沒有 gcc 環境,則需要安裝: cd /etc/yum.repos.d/ sed -i 's/mirrorlist/#mirrorlist/g' /etc/yu ...
  • 基於java高校獎學金管理系統設計與實現,可適用於大學獎學金管理系統,學生獎學金管理系統,學校獎學金,校園獎學金申請管理系統; ...
  • 除了繪製各類分析圖形(比如柱狀圖,折線圖,餅圖等等)以外,matplotlib 也可以在畫布上任意繪製各類幾何圖形。這對於電腦圖形學、幾何演算法和電腦輔助設計等領域非常重要。 matplitlib 中的 patches 類提供了豐富的幾何對象,本篇拋磚引玉,介紹其中幾種常用的幾何圖形繪製方法。 其 ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...