Java 誕生距今已有 25 年,但它仍然長期占據(jù)著“天下第一”編程語言的寶座。只是其統(tǒng)治地位并非堅不可摧,反倒可以說是危機四伏。云原生時代,Java 技術(shù)體系的許多前提假設(shè)都受到了挑戰(zhàn),目前已經(jīng)有可預見的、足以威脅動搖其根基的潛在可能性正在醞釀。同時,像 Golang、Rust 這樣的新生語言,以及 C、C++、C#、Python 等老對手也都對 Java 的市場份額虎視眈眈。面對危機,Java 正在嘗試哪些變革?未來,Java 是會繼續(xù)向前、再攀高峰,還是由盛轉(zhuǎn)衰?在今天由極客邦科技舉辦的 QCon 全球軟件開發(fā)大會 2020(深圳站)上,遠光軟件研究院院長、《深入理解 Java 虛擬機》系列書籍作者周志明發(fā)表了主題演講《云原生時代的 Java》,以下內(nèi)容為演講整理。
今天,25歲的Java仍然是最具有統(tǒng)治力的編程語言,長期占據(jù)編程語言排行榜的首位,擁有一千二百萬的龐大開發(fā)者群體,全世界有四百五十億部物理設(shè)備使用著Java技術(shù),同時,在云端數(shù)據(jù)中心的虛擬化環(huán)境里,還運行著超過兩百五十億個Java虛擬機的進程實例(數(shù)據(jù)來自O(shè)racle的WebCast)。
以上這些數(shù)據(jù)是Java過去25年巨大成就的功勛佐證,更是Java技術(shù)體系維持自己“天下第一”編程語言的堅實壁壘。Java與其他語言競爭,底氣從來不在于語法、類庫有多么先進好用,而是來自它龐大的用戶群和極其成熟的軟件生態(tài),這在朝夕之間難以撼動。然而,這個現(xiàn)在看起來仍然堅不可摧的Java帝國,其統(tǒng)治地位的穩(wěn)固程度不僅沒有高枕無憂,反而說是危機四伏也不為過。目前已經(jīng)有了可預見的、足以威脅動搖其根基的潛在可能性正在醞釀,并隨云原生時代而降臨。
Java 的危機
Java與云原生的矛盾,來源于Java誕生之初,植入到它基因之中的一些基本的前提假設(shè)已經(jīng)逐漸開始被動搖,甚至已經(jīng)不再成立。
我舉個例子,每一位Java的使用者都聽說過“一次編寫,到處運行”(Write Once, Run Anywhere)這句口號。20多年前,Java成熟之前,開發(fā)者如果希望程序在Linux、Solaris、Windows等不同平臺,在x86、AMD64、SPARC、MIPS、ARM等不同指令集架構(gòu)上都能正常運行,就必須針對每種組合,編譯出對應(yīng)的二進制發(fā)行包,或者索性直接分發(fā)源代碼,由使用者在自己的平臺上編譯。
面對這個問題,Java通過語言層虛擬化的方式,令每一個Java應(yīng)用都自動取得平臺無關(guān)(Platform Independent)、架構(gòu)中立(Architecture Neutral)的先天優(yōu)勢,讓同一套程序格式得以在不同指令集架構(gòu)、不同操作系統(tǒng)環(huán)境下都能運行且得到一致的結(jié)果,不僅方便了程序的分發(fā),還避免了各種平臺下內(nèi)存模型、線程模型、字節(jié)序等底層細節(jié)差異對程序編寫的干擾。在當年,Java的這種設(shè)計帶有令人趨之若鶩的強大吸引力,直接開啟了托管語言(Managed Language,如Java、.NET)的一段興盛期。
面對相同的問題,今天的云原生選擇以操作系統(tǒng)層虛擬化的方式,通過容器實現(xiàn)的不可變基礎(chǔ)設(shè)施去解決。不可變基礎(chǔ)設(shè)施這個概念出現(xiàn)得比云原生要早,原本是指該如何避免由于運維人員對服務(wù)器運行環(huán)境所做的持續(xù)的變更而導致的意想不到的副作用。但在云原生時代,它的內(nèi)涵已不再局限于方便運維、程序升級和部署的手段,而是升華一種為向應(yīng)用代碼隱藏環(huán)境復雜性的手段,是分布式服務(wù)得以成為一種可普遍推廣的普適架構(gòu)風格的必要前提。
將程序連同它的運行環(huán)境一起封裝到穩(wěn)定的鏡像里,現(xiàn)已是一種主流的應(yīng)用程序分發(fā)方式。Docker同樣提出過“一次構(gòu)建,到處運行”(Build Once, Run Anywhere)的口號,盡管它只能提供環(huán)境兼容性和有局限的平臺無關(guān)性(指系統(tǒng)內(nèi)核功能以上的ABI兼容),且完全不可能支撐架構(gòu)中立性,所以將“一次構(gòu)建,到處運行”與“一次編寫,到處運行”對立起來并不嚴謹恰當,但是無可否認,今天Java技術(shù)“一次編譯,到處運行”的優(yōu)勢,已經(jīng)被容器大幅度地削弱,不再是大多數(shù)服務(wù)端開發(fā)者技術(shù)選型的主要考慮因素了。
如果僅僅是優(yōu)勢的削弱,并不足以成為Java的直接威脅,充其量只是一個潛在的不利因素,但更加迫在眉睫的風險來自于那些與技術(shù)潮流直接沖突的假設(shè)。譬如,Java總體上是面向大規(guī)模、長時間的服務(wù)端應(yīng)用而設(shè)計的,嚴(luō)謹(suō)的語法利于約束所有人寫出較一致的代碼;靜態(tài)類型動態(tài)鏈接的語言結(jié)構(gòu),利于多人協(xié)作開發(fā),讓軟件觸及更大規(guī)模;即時編譯器、性能制導優(yōu)化、垃圾收集子系統(tǒng)等Java最具代表性的技術(shù)特征,都是為了便于長時間運行的程序能享受到硬件規(guī)模發(fā)展的紅利。
另一方面,在微服務(wù)的背景下,提倡服務(wù)圍繞業(yè)務(wù)能力而非技術(shù)來構(gòu)建應(yīng)用,不再追求實現(xiàn)上的一致,一個系統(tǒng)由不同語言,不同技術(shù)框架所實現(xiàn)的服務(wù)來組成是完全合理的;服務(wù)化拆分后,很可能單個微服務(wù)不再需要再面對數(shù)十、數(shù)百GB乃至TB的內(nèi)存;有了高可用的服務(wù)集群,也無須追求單個服務(wù)要7×24小時不可間斷地運行,它們隨時可以中斷和更新。
同時,微服務(wù)又對應(yīng)用的容器化親和性,譬如鏡像體積、內(nèi)存消耗、啟動速度,以及達到最高性能的時間等方面提出了新的要求。這兩年的網(wǎng)紅概念Serverless也進一步增加這些因素的考慮權(quán)重,而這些卻正好都是Java的弱項:哪怕再小的Java程序也要帶著完整的虛擬機和標準類庫,使得鏡像拉取和容器創(chuàng)建效率降低,進而使整個容器生命周期拉長。基于Java虛擬機的執(zhí)行機制,使得任何Java的程序都會有固定的基礎(chǔ)內(nèi)存開銷,以及固定的啟動時間,而且Java生態(tài)中廣泛采用的依賴注入進一步將啟動時間拉長,使得容器的冷啟動時間很難縮短。
軟件工業(yè)中已經(jīng)出現(xiàn)過不止一起因Java這些弱點而導致失敗的案例,如JRuby編寫的Logstash,原本是同時承擔部署在節(jié)點上的收集端(Shipper)和專門轉(zhuǎn)換處理的服務(wù)端(Master)的職責,后來因為資源占用的原因,被Elstaic.co用Golang的Filebeat代替了Shipper部分的職能;又如Scala語言編寫的邊車代理Linkerd,作為服務(wù)網(wǎng)格概念的提出者,卻最終被Envoy所取代,其主要弱點之一也是由于Java虛擬機的資源消耗所帶來的劣勢。
雖然在云原生時代依然有很多適合Java發(fā)揮的領(lǐng)域,但是具備彈性與韌性、隨時可以中斷重啟的微型服務(wù)的確已經(jīng)形成了一股潮流,在逐步蠶食大型系統(tǒng)的領(lǐng)地。正是由于潮流趨勢的改變,新一代的語言與技術(shù)尤其重視輕量化和快速響應(yīng)能力,大多又重新回歸到了原生語言(Native Language,如Golang、Rust)之上。
Java 的變革
面對挑戰(zhàn),Java的開發(fā)者和社區(qū)都沒有退縮,它們在各自的領(lǐng)域給出了很多優(yōu)秀的解決方案,涌現(xiàn)了如Quarkus、Micronaut、Helidon等一大批以提升Java在云原生環(huán)境下的適應(yīng)性為賣點的框架。
不過,今天我們的主題將聚焦在由Java官方本身所推進的項目上。在圍繞Java 25周年的研討和布道活動中,官方的設(shè)定是以“面向未來的變革”(Innovating for the Future)為基調(diào),你有可能在此之前已經(jīng)聽說過其中某個(某些)項目的名字和改進點,但這里我們不僅關(guān)心這些項目改進的是什么,還更關(guān)心它們背后的動機與困難、帶來的收益,以及要付出的代價。
Innovating for the Future
Project Leyden
對于原生語言的挑戰(zhàn),最有力最徹底的反擊手段無疑是將字節(jié)碼直接編譯成可以脫離Java虛擬機的原生代碼。如果真的能夠生成脫離Java虛擬機運行的原生程序,將意味著啟動時間長的問題能夠徹底解決,因為此時已經(jīng)不存在初始化虛擬機和類加載的過程;也意味著程序馬上就能達到最佳的性能,因為此時已經(jīng)不存在即時編譯器運行時編譯,所有代碼都是在編譯期編譯和優(yōu)化好的(如下圖所示);沒有了Java虛擬機、即時編譯器這些額外的部件,也就意味著能夠省去它們原本消耗的那部分內(nèi)存資源與鏡像體積。
Java Performance Matrices(圖片來源)
但同時,這也是風險系數(shù)最高、實現(xiàn)難度最大的方案。
Java并非沒有嘗試走過這條路,從Java 2之前的GCJ(GNU Compiler for Java),到后來的Excelsior JET,再到2018年Oracle Labs啟動的GraalVM中的SubstrateVM模塊,最后到2020年中期剛建立的Leyden項目,都在朝著提前編譯(Ahead-of-Time Compilation,AOT)生成原生程序這個目標邁進。
Java支持提前編譯最大的困難在于它是一門動態(tài)鏈接的語言,它假設(shè)程序的代碼空間是開放的(Open World),允許在程序的任何時候通過類加載器去加載新的類,作為程序的一部分運行。要進行提前編譯,就必須放棄這部分動態(tài)性,假設(shè)程序的代碼空間是封閉的(Closed World),所有要運行的代碼都必須在編譯期全部可知。這一點不僅僅影響到了類加載器的正常運作,除了無法再動態(tài)加載外,反射(通過反射可以調(diào)用在編譯期不可知的方法)、動態(tài)代理、字節(jié)碼生成庫(如CGLib)等一切會運行時產(chǎn)生新代碼的功能都不再可用,如果將這些基礎(chǔ)能力直接抽離掉,Helloworld還是能跑起來,但Spring肯定跑不起來,Hibernate也跑不起來,大部分的生產(chǎn)力工具都跑不起來,整個Java生態(tài)中絕大多數(shù)上層建筑都會轟然崩塌。
要獲得有實用價值的提前編譯能力,只有依靠提前編譯器、組件類庫和開發(fā)者三方一起協(xié)同才可能辦到。由于Leyden剛剛開始,幾乎沒有公開的資料,所以下面我是以SubstrateVM為目標對象進行的介紹:
有一些功能,像反射這樣的基礎(chǔ)特性是不可能妥協(xié)的,折衷的解決辦法是由用戶在編譯期,以配置文件或者編譯器參數(shù)的形式,明確告知編譯器程序代碼中有哪些方法是只通過反射來訪問的,編譯器將方法的添加到靜態(tài)編譯的范疇之中。同理,所有使用到動態(tài)代理的地方,也必須在事先列明,在編譯期就將動態(tài)代理的字節(jié)碼全部生成出來。其他所有無法通過程序指針分析(Points-To Analysis)得到的信息,譬如程序中用到的資源、配置文件等等,也必須照此處理。
另一些功能,如動態(tài)生成字節(jié)碼也十分常用,但用戶自己往往無法得知那些動態(tài)字節(jié)碼的具體信息,就只能由用到CGLib、javassist等庫的程序去妥協(xié)放棄。在Java世界中也許最典型的場景就是Spring用CGLib來進行類增強,默認情況下,每一個Spring管理的Bean都要用到CGLib。從Spring Framework 5.2開始增加了@proxyBeanMethods注解來排除對CGLib的依賴,僅使用標準的動態(tài)代理去增強類。
2019年起,Pivotal的Spring團隊與Oracle Labs的GraalVM團隊共同孵化了Spring GraalVM Native項目,這個目前仍處于Experimental / Alpha狀態(tài)的項目,能夠讓程序先以傳統(tǒng)方式運行(啟動)一次,自動化地找出程序中的反射、動態(tài)代理的代碼,代替用戶向編譯器提供絕大部分所需的信息,并能將允許啟動時初始化的Bean在編譯期就完成初始化,直接繞過Spring程序啟動最慢的階段。這樣從啟動到程序可以提供服務(wù),耗時竟能夠低于0.1秒。
Spring Boot Startup Time(數(shù)據(jù)來源)
以原生方式運行后,縮短啟動時間的效果立竿見影,一般會有數(shù)十倍甚至更高的改善,程序容量和內(nèi)存消耗也有一定程度的下降。不過至少目前而言,程序的運行效率還是要弱于傳統(tǒng)基于Java虛擬機的方式,雖然即時編譯器有編譯時間的壓力,但由于可以進行基于假設(shè)的激進優(yōu)化和運行時性能度量的制導優(yōu)化,使得即時編譯器的效果仍要優(yōu)于提前編譯器,這方面需要GraalVM編譯器團隊的進一步努力,也需要從語言改進上入手,讓Java變得更適合被編譯器優(yōu)化。
Project Valhalla
Java語言上可感知的語法變化,多數(shù)來自于Amber項目,它的項目目標是持續(xù)優(yōu)化語言生產(chǎn)力,近期(JDK 15、16)會有很多來自這個項目的特性,如Records、Sealed Class、Pattern Matching、Raw String Literals等實裝到生產(chǎn)環(huán)境。
然而語法不僅與編碼效率相關(guān),與運行效率也有很大關(guān)系。“程序=代碼+數(shù)據(jù)”這個提法至少在衡量運行效率上是合適的,無論是托管語言還是原生語言,最終產(chǎn)物都是處理器執(zhí)行的指令流和內(nèi)存存儲的數(shù)據(jù)結(jié)構(gòu)。Java、.NET、C、C++、Golang、Rust等各種語言誰更快,取決于特定場景下,編譯器生成指令流的優(yōu)化效果,以及數(shù)據(jù)在內(nèi)存中的結(jié)構(gòu)布局。
Java即時編譯器的優(yōu)化效果拔群,但是由于Java“一切皆為對象”的前提假設(shè),導致在處理一系列不同類型的小對象時,內(nèi)存訪問性能非常拉垮,這點是Java在游戲、圖形處理等領(lǐng)域一直難有建樹的重要制約因素,也是Java建立Valhalla項目的目標初衷。
這里舉個例子來說明此問題,如果我想描述空間里面若干條線段的集合,在Java中定義的代碼會是這樣的:
面向?qū)ο蟮膬?nèi)存布局中,對象標識符(Object Identity)存在的目的是為了允許在不暴露對象結(jié)構(gòu)的前提下,依然可以引用其屬性與行為,這是面向?qū)ο缶幊讨卸鄳B(tài)性的基礎(chǔ)。在Java中堆內(nèi)存分配和回收、空值判斷、引用比較、同步鎖等一系列功能都會涉及到對象標識符,內(nèi)存訪問也是依靠對象標識符來進行鏈式處理的,譬如上面代碼中的“若干條線段的集合”,在堆內(nèi)存中將構(gòu)成如下圖的引用關(guān)系:
Object Identity / Memory Layout
計算機硬件經(jīng)過25年的發(fā)展,內(nèi)存與處理器雖然都在進步,但是內(nèi)存延遲與處理器執(zhí)行性能之間的馮諾依曼瓶頸(Von Neumann Bottleneck)不僅沒有縮減,反而還在持續(xù)加大,“RAM Is the New Disk”已經(jīng)從嘲諷梗逐漸成為了現(xiàn)實。
一次內(nèi)存訪問(將主內(nèi)存數(shù)據(jù)調(diào)入處理器Cache)大約需要耗費數(shù)百個時鐘周期,而大部分簡單指令的執(zhí)行只需要一個時鐘周期而已。因此,在程序執(zhí)行性能這個問題上,如果編譯器能減少一次內(nèi)存訪問,可能比優(yōu)化掉幾十、幾百條其他指令都來得更有效果。
額外知識:馮諾依曼瓶頸
不同處理器(現(xiàn)代處理器都集成了內(nèi)存管理器,以前是在北橋芯片中)的內(nèi)存延遲大概是40-80納秒(ns,十億分之一秒),而根據(jù)不同的時鐘頻率,一個時鐘周期大概在0.2-0.4納秒之間,如此短暫的時間內(nèi),即使真空中傳播的光,也僅僅能夠行進10厘米左右。
數(shù)據(jù)存儲與處理器執(zhí)行的速度矛盾是馮諾依曼架構(gòu)的主要局限性之一,1977年的圖靈獎得主John Backus提出了“馮諾依曼瓶頸”這個概念,專門用來描述這種局限性。
編譯器的確在努力減少內(nèi)存訪問,從JDK 6起,HotSpot的即時編譯器就嘗試通過逃逸分析來做標量替換(Scalar Replacement)和棧上分配(Stack Allocations)優(yōu)化,基本原理是如果能通過分析,得知一個對象不會傳遞到方法之外,那就不需要真實地在對中創(chuàng)建完整的對象布局,完全可以繞過對象標識符,將它拆散為基本的原生數(shù)據(jù)類型來創(chuàng)建,甚至是直接在棧內(nèi)存中分配空間(HotSpot并沒有這樣做),方法執(zhí)行完畢后隨著棧幀一起銷毀掉。
不過,逃逸分析是一種過程間優(yōu)化(Interprocedural Optimization),非常耗時,也很難處理那些理論有可能但實際不存在的情況。相同的問題在C、C++中卻并不存在,上面場景中,程序員只要將Point和Line都定義為struct即可,C#中也有struct,是依靠.NET的值類型(Value Type)來實現(xiàn)的。Valhalla項目的核心改進就是提供類似的值類型支持,提供一個新的關(guān)鍵字(inline),讓用戶可以在不需要向方法外部暴露對象、不需要多態(tài)性支持、不需要將對象用作同步鎖的場合中,將類標識為值類型,此時編譯器就能夠繞過對象標識符,以平坦的、緊湊的方式去為對象分配內(nèi)存。
有了值類型的支持后,現(xiàn)在Java泛型中令人詬病的不支持原數(shù)據(jù)類型(Primitive Type)、頻繁裝箱問題也就隨之迎刃而解,現(xiàn)在Java的包裝類,理所當然地會以代表原生類型的值類型來重新定義,這樣Java泛型的性能會得到明顯的提升,因為此時Integer與int的訪問,在機器層面看完全可以達到一致的效率。
Project Loom
Java語言抽象出來隱藏了各種操作系統(tǒng)線程差異性的統(tǒng)一線程接口,這曾經(jīng)是它區(qū)別于其他編程語言(C/C++表示有被冒犯到)的一大優(yōu)勢,不過,統(tǒng)一的線程模型不見得永遠都是正確的。
Java目前主流的線程模型是直接映射到操作系統(tǒng)內(nèi)核上的1:1模型,這對于計算密集型任務(wù)這很合適,既不用自己去做調(diào)度,也利于一條線程跑滿整個處理器核心。但對于I/O密集型任務(wù),譬如訪問磁盤、訪問數(shù)據(jù)庫占主要時間的任務(wù),這種模型就顯得成本高昂,主要在于內(nèi)存消耗和上下文切換上:64位Linux上HotSpot的線程棧容量默認是1MB,線程的內(nèi)核元數(shù)據(jù)(Kernel Metadata)還要額外消耗2-16KB內(nèi)存,所以單個虛擬機的最大線程數(shù)量一般只會設(shè)置到200至400條,當程序員把數(shù)以百萬計的請求往線程池里面灌時,系統(tǒng)即便能處理得過來,其中的切換損耗也相當可觀。
Loom項目的目標是讓Java支持額外的N:M線程模型,請注意是“額外支持”,而不是像當年從綠色線程過渡到內(nèi)核線程那樣的直接替換,也不是像Solaris平臺的HotSpot虛擬機那樣通過參數(shù)讓用戶二選其一。
Loom項目新增加一種“虛擬線程”(Virtual Thread,以前以Fiber為名進行宣傳過,但因為要頻繁解釋啥是Fiber所以現(xiàn)在放棄了),本質(zhì)上它是一種有棧協(xié)程(Stackful Coroutine),多條虛擬線程可以映射到同一條物理線程之中,在用戶空間中自行調(diào)度,每條虛擬線程的棧容量也可由用戶自行決定。
Virtual Thread
同時,Loom項目的另一個目標是要盡最大可能保持原有統(tǒng)一線程模型的交互方式,通俗地說就是原有的Thread、J.U.C、NIO、Executor、Future、ForkJoinPool等這些多線程工具都應(yīng)該能以同樣的方式支持新的虛擬線程,原來多線程中你理解的概念、編碼習慣大多數(shù)都能夠繼續(xù)沿用。
為此,虛擬線程將會與物理線程一樣使用java.lang.Thread來進行抽象,只是在創(chuàng)建線程時用到的參數(shù)或者方法稍有不同(譬如給Thread增加一個Thread.VIRTUAL_THREAD參數(shù),或者增加一個startVirtualThread()方法)。這樣現(xiàn)有的多線程代碼遷移到虛擬線程中的成本就會變得很低,而代價就是Loom的團隊必須做更多的工作以保證虛擬線程在大部分涉及到多線程的標準API中都能夠兼容,甚至在調(diào)試器上虛擬線程與物理線程看起來都會有一致的外觀。但很難全部都支持,譬如調(diào)用JNI的本地棧幀就很難放到虛擬線程上,所以一旦遇到本地方法,虛擬線程就會被綁定(Pinned)到一條物理線程上。
Loom的另一個重點改進是支持結(jié)構(gòu)化并發(fā)(Structured Concurrency),這是2016年才提出的新的并發(fā)編程概念,但很快就被諸多編程語言所吸納。它是指程序的并發(fā)行為會與代碼的結(jié)構(gòu)對齊,譬如以下代碼所示,按照傳統(tǒng)的編程觀念,如果沒有額外的處理(譬如無中生有地弄一個await關(guān)鍵字),那在task1和task2提交之后,程序應(yīng)該繼續(xù)向下執(zhí)行:
但是在結(jié)構(gòu)化并發(fā)的支持下,只有兩個并行啟動的任務(wù)線程都結(jié)束之后,程序才會繼續(xù)向下執(zhí)行,很好地以同步的編碼風格,來解決異步的執(zhí)行問題。事實上,“Code like sync,Work like async”正是Loom簡化并發(fā)編程的核心理念。
Project Portola
Portola項目的目標是將OpenJDK向Alpine Linux移植。Alpine Linux是許多Docker容器首選的基礎(chǔ)鏡像,因為它只有5 MB大小,比起其他Cent OS、Debain等動輒一百多MB的發(fā)行版來說,更適合用于容器環(huán)境。不過Alpine Linux為了盡量瘦身,默認是用musl作為C標準庫的,而非傳統(tǒng)的glibc(GNU C library),因此要以Alpine Linux為基礎(chǔ)制作OpenJDK鏡像,必須先安裝glibc,此時基礎(chǔ)鏡像大約有12 MB。Portola計劃將OpenJDK的上游代碼移植到musl,并通過兼容性測試。使用Portola制作的標準Java SE 13鏡像僅有41 MB,不僅遠低于Cent OS的OpenJDK(大約396 MB),也要比官方的slim版(約200 MB)要小得多。
Java 的未來
云原生時代,Java技術(shù)體系的許多前提假設(shè)都受到了挑戰(zhàn),“一次編譯,到處運行”、“面向長時間大規(guī)模程序而設(shè)計”、“從開放的代碼空間中動態(tài)加載”、“一切皆為對象”、“統(tǒng)一線程模型”,等等。技術(shù)發(fā)展迭代不會停歇,沒有必要堅持什么“永恒的真理”,舊的原則被打破,只要合理,便是創(chuàng)新。
Java語言意識到了挑戰(zhàn),也意識到了要面向未來而變革。文中提到的這些項目,Amber和Portola已經(jīng)明確會在2021年3月的Java 16中發(fā)布,至少也會達到Feature Preview的程度:
JEP 394:Pattern Matching for instanceof
JEP 395:Records
JEP 397:Sealed Classes
JEP 386:Alpine Linux Port
至于更受關(guān)注,同時也是難度更高的 Valhalla 和 Loom 項目,目前仍然沒有明確的版本計劃信息,盡管它們已經(jīng)開發(fā)了數(shù)年時間,非常希望能夠趕在 Java 17 這個 LTS 版本中面世,但前路還是困難重重。
至于難度最高、創(chuàng)建時間最晚的 Leyden 項目,目前還完全處于特性討論階段,連個胚胎都算不上。對于 Java 的原生編譯,我們中短期內(nèi)只可能寄希望于 Oracle 的 GraalVM。
未來一段時間,是Java重要的轉(zhuǎn)型窗口期,如果作為下一個LTS版的Java 17,能夠成功集Amber、Portola、Valhalla、Loom和Panama(用于外部函數(shù)接口訪問,本文沒有提到)的新能力、新特性于一身,GraalVM也能給予足夠強力支持的話,那Java 17 LTS大概率會是一個里程碑式的版本,帶領(lǐng)著整個Java生態(tài)從大規(guī)模服務(wù)端應(yīng)用,向新的云原生時代軟件系統(tǒng)轉(zhuǎn)型。可能成為比肩當年從面向嵌入式設(shè)備與瀏覽器Web Applets的Java 1,到確立現(xiàn)代Java語言方向(Java SE/EE/ME和JavaCard)雛形的Java 2轉(zhuǎn)型那樣的里程碑。
但是,如果Java不能加速自己的發(fā)展步伐,那由強大生態(tài)所構(gòu)建的護城河終究會消耗殆盡,被Golang、Rust這樣的新生語言,以及C、C++、C#、Python等老對手蠶食掉很大一部分市場份額,以至被迫從“天下第一”編程語言的寶座中退位。
Java的未來是繼續(xù)向前,再攀高峰,還是由盛轉(zhuǎn)衰,鋒芒挫縮,你我拭目以待。
責編AJX
-
JAVA
+關(guān)注
關(guān)注
20文章
2986瀏覽量
107089 -
編程
+關(guān)注
關(guān)注
88文章
3685瀏覽量
94929 -
云原生
+關(guān)注
關(guān)注
0文章
257瀏覽量
8222
發(fā)布評論請先 登錄
從 Java 到 Go:面向?qū)ο蟮木奕伺c云原生的輕騎兵
云原生在汽車行業(yè)的優(yōu)勢
云原生AI服務(wù)怎么樣
云原生LLMOps平臺作用
如何選擇云原生機器學習平臺
構(gòu)建云原生機器學習平臺流程
什么是云原生MLOps平臺
梯度科技入選2024云原生企業(yè)TOP50榜單
云原生和數(shù)據(jù)庫哪個好一些?
k8s微服務(wù)架構(gòu)就是云原生嗎?兩者是什么關(guān)系
云原生和非云原生哪個好?六大區(qū)別詳細對比
中科馭數(shù)分析DPU在云原生網(wǎng)絡(luò)與智算網(wǎng)絡(luò)中的實際應(yīng)用
京東云原生安全產(chǎn)品重磅發(fā)布

從積木式到裝配式云原生安全

基于DPU與SmartNic的云原生SDN解決方案

評論