1. 程式人生 > 其它 >JDK11新特性

JDK11新特性

JDK11新特性

前言

北京時間 2018年9 月 26 日,Oracle 官方宣佈 Java 11 正式釋出。這是 Java 大版本週期變化後的第一個長期支援版本,非常值得關注。從官網即可下載, 最新發布的 Java11 將帶來 ZGC、Http Client 等重要特性,一共包含 17 個 JEP(JDK Enhancement Proposals,JDK 增強提案)。

JDK 11 將是一個 企業不可忽視的版本。從時間節點來看,JDK 11 的釋出正好處在 JDK 8 免費更新到期的前夕,同時 JDK 9、10 也陸續成為“歷史版本”

JDK 11 是一個長期支援版本(LTS, Long-Term-Support )

從 JVM GC 的角度,JDK11 引入了兩種新的 GC,其中包括也許是劃時代意義的 ZGC,雖然其目前還是實驗特性,但是從能力上來看,這是 JDK 的一個巨大突破,為特定生產環境的苛刻需求提供了一個可能的選擇。例如,對部分企業核心儲存等產品,如果能夠保證不超過 10ms 的 GC 暫停,可靠性會上一個大的臺階,這是過去我們進行 GC 調優幾乎做不到的,是能與不能的問題。

對於 G1 GC,相比於 JDK 8,升級到 JDK 11 即可免費享受到:並行的 Full GC,快速的 CardTable 掃描,自適應的堆佔用比例調整(IHOP),在併發標記階段的型別解除安裝等等。這些都是針對 G1 的不斷增強,其中序列 Full GC 等甚至是曾經被廣泛詬病的短板,你會發現 GC 配置和調優在 JDK11 中越來越方便。

雲端計算時代的監控、診斷和 Profiling 能力,這個是相比 ZGC 更具生產實踐意義的特性。

JFR 是一套整合進入 JDK、JVM 內部的事件機制框架,通過良好架構和設計的框架,硬體層面的極致優化,生產環境的廣泛驗證,它可以做到極致的可靠和低開銷。在 SPECjbb2015 等基準測試中,JFR 的效能開銷最大不超過 1%,所以,工程師可以基本沒有心理負擔地在大規模分散式的生產系統使用,這意味著,我們既可以隨時主動開啟 JFR 進行特定診斷,也可以讓系統長期執行 JFR,用以在複雜環境中進行“After-the-fact”分析。

在保證低開銷的基礎上,JFR 提供的能力可以應用在對鎖競爭、阻塞、延遲,JVM GC、SafePoint 等領域,進行非常細粒度分析。甚至深入 JIT Compiler 內部,全面把握熱點方法、內聯、逆優化等等。JFR 提供了標準的 Java、C++ 等擴充套件 API,可以與各種層面的應用進行定製、整合,為複雜的企業應用棧或者複雜的分散式應用,提供 All-in-One 解決方案。

Low-Overhead Heap Profiling它來源於 Google 等業界前沿廠商的一線實踐,通過獲取物件分配細節,為 JDK 補足了物件分配診斷方面的一些短板,工程師可以通過 JVMTI 使用這個能力增強自身的工具。

從 Java 類庫發展的角度來看,JDK 11 最大的進步也是兩個方面:

第一, HTTP/2 Client API,新的 HTTP API 提供了對 HTTP/2 等業界前沿標準的支援,精簡而又友好的 API 介面,與主流開源 API(如,Apache HttpClient, Jetty, OkHttp 等)對等甚至更高的效能。與此同時它是 JDK 在 Reactive-Stream 方面的第一個生產實踐,廣泛使用了 Java Flow API 等,終於讓 Java 標準 HTTP 類庫在擴充套件能力等方面,滿足了現代網際網路的需求。

第二,就是安全類庫、標準等方面的大範圍升級,其中特別是 JEP 332: Transport Layer Security (TLS) 1.3,除了在安全領域的重要價值,它還是中國安全專家範學雷所領導的 JDK 專案,完全不同於以往的修修補補,是個非常大規模的工程。

除此之外,JDK 還在逐漸進行瘦身工作,或者償還 JVM、Java 規範等歷史欠賬

官方的更新列表如下 :
JEP 181: Nest-Based Access Control
JEP 309: Dynamic Class-File Constants
JEP 315: Improve Aarch64 Intrinsics
JEP 318: Epsilon: A No-Op Garbage Collector
JEP 320: Remove the Java EE and CORBA Modules
JEP 321: HTTP Client (Standard)
JEP 323: Local-Variable Syntax for Lambda Parameters
JEP 324: Key Agreement with Curve25519 and Curve448
JEP 327: Unicode 10
JEP 328: Flight Recorder
JEP 329: ChaCha20 and Poly1305 Cryptographic Algorithms
JEP 330: Launch Single-File Source-Code Programs
JEP 331: Low-Overhead Heap Profiling
JEP 332: Transport Layer Security (TLS) 1.3
JEP 333: ZGC: A Scalable Low-Latency Garbage Collector (Experimental)
JEP 335: Deprecate the Nashorn JavaScript Engine
JEP 336: Deprecate the Pack200 Tools and API
注 : JEP (JDK Enhancement Proposal 特性增強提議)

JShell

java9引入了jshell這個互動性工具,讓Java也可以像指令碼語言一樣來執行,可以從控制檯啟動 jshell ,在 jshell 中直接輸入表示式並檢視其執行結果。當需要測試一個方法的執行效果,或是快速的對錶達式進行求值時,jshell 都非常實用。

除了表示式之外,還可以建立 Java 類和方法。jshell 也有基本的程式碼完成功能。我們在教人們如何編寫 Java 的過程中,不再需要解釋 “public static void main(String [] args)” 這句廢話。

1. 首先命令列輸入jshell
2. 按照提示,繼續輸入/help intro

Jshell使用

Dynamic Class-File Constants類檔案新添的一種結構

Java的型別檔案格式將被拓展,支援一種新的常量池格式:CONSTANT_Dynamic,載入CONSTANT_Dynamic會將建立委託給bootstrap方法。

其目標是降低開發新形式的可實現類檔案約束帶來的成本和干擾。

區域性變數型別推斷(var ”關鍵字”)

這並不代表java為弱型別語言,java依舊為強型別語言,這只是一種編譯器的型別推斷語法

var javastack = "javastack";
System.out.println(javastack);
/**
 * var javastack = "javastack";
 * 就等於:
 * String javastack = "javastack";
 */

部變數型別推斷就是左邊的型別直接使用 var 定義,而不用寫具體的型別,編譯器能根據右邊的表示式自動推斷型別,如上面的 String 。

在宣告隱式型別的lambda表示式的形參時允許使用var

使用var的好處是在使用lambda表示式時給引數加上註解 (不寫型別是無法添加註解的)

(@Deprecated var x, @Nullable var y) -> x.process(y);

var 語法 : 區域性變數的型別推斷.
注意點 : 
	1) var a; 這樣不可以, 因為無法推斷.
	2) 類的屬性的資料型別不可以使用var.
	
有引數的lambda表示式使用
函式式介面 : 
	Consumer<T> : 消費型函式式介面.
		public void accept(T t);
		
	Consumer<String> consumer = t -> System.out.println(t.toUpperCase());
	
	Consumer<String> consumer = (var t) -> System.out.println(t.toUpperCase());
	
	錯誤的形式: 必須要有型別, 可以加上var
	Consumer<String> consumer = (@Deprecated t) -> System.out.println(t.toUpperCase());
	正確的形式:
	Consumer<String> consumer = (@Deprecated var t) -> System.out.println(t.toUpperCase());

新加一些實用的API

新的本機不可修改集合API。

自 Java 9 開始,Jdk 裡面為集合(List/ Set/ Map)都添加了 of 和 copyOf 方法,它們兩個都用來建立不可變的集合,來看下它們的使用和區別。

// 例1
var list = List.of("Java", "Python", "C");
var copy = List.copyOf(list);
System.out.println(list == copy); // true

// 例2
var list = new ArrayList<String>();
var copy = List.copyOf(list);
System.out.println(list == copy); // false

示例1和2程式碼差不多,為什麼一個為true,一個為false?

// 來看下它們的原始碼:

static <E> List<E> of(E... elements) {
  switch (elements.length) { // implicit null check of elements
    case 0:
        return ImmutableCollections.emptyList();
    case 1:
        return new ImmutableCollections.List12<>(elements[0]);
    case 2:
        return new ImmutableCollections.List12<>(elements[0], elements[1]);
    default:
        return new ImmutableCollections.ListN<>(elements);
  }
}

static <E> List<E> copyOf(Collection<? extends E> coll) {
    return ImmutableCollections.listCopy(coll);
}

static <E> List<E> listCopy(Collection<? extends E> coll) {
    if (coll instanceof AbstractImmutableList && coll.getClass() != SubList.class) {
        return (List<E>)coll;
    } else {
        return (List<E>)List.of(coll.toArray());
    }
}

可以看出 copyOf 方法會先判斷來源集合是不是 AbstractImmutableList 型別的,如果是,就直接返回,如果不是,則呼叫 of 建立一個新的集合。

示例2中因為用的 new 建立的集合,不屬於不可變 AbstractImmutableList 類的子類,所以 copyOf 方法又建立了一個新的例項,所以為false.

注意:使用of和copyOf建立的集合為不可變集合,不能進行新增、刪除、替換、排序等操作,不然會報 java.lang.UnsupportedOperationException 異常。

上面演示了 List 的 of 和 copyOf 方法,Set 和 Map 介面都有。

除了更短和更好閱讀之外,這些方法也可以避免您選擇特定的集合實現。在建立後,繼續新增元素到這些集合會導致 “UnsupportedOperationException”

Stream 加強

Stream 是 Java 8 中的新特性,Java 9 開始對 Stream 增加了以下 4 個新方法

  1. 增加單個引數構造方法,可為null

    Stream.ofNullable(null).count(); // 0
    
  2. 增加 takeWhile 和 dropWhile 方法

// 從開始計算,當 n < 3 時就截止。
Stream.of(1, 2, 3, 2, 1)
	  .takeWhile(n -> n < 3)
	  .collect(Collectors.toList()); // [1, 2]

// 這個和上面的相反,一旦 n < 3 不成立就開始計算。
Stream.of(1, 2, 3, 2, 1)
	  .dropWhile(n -> n < 3)
	  .collect(Collectors.toList()); // [3, 2, 1]
  1. iterate過載

    這個 iterate 方法的新過載方法,可以讓你提供一個 Predicate (判斷條件)來指定什麼時候結束迭代。

    // 流的迭代, 建立流(原來,只能通過limit控制數量,侷限性很大)
    Stream<Integer> stream1 = Stream.iterate(1, t -> (2 * t) + 1);
    stream1.limit(10).forEach(System.out::println);
    		
    // 有限的迭代(新增迭代條件 t < 1000)
    Stream<Integer> stream2 = Stream.iterate(1, t -> t < 1000, t -> (2 * t) + 1);
    stream2.forEach(System.out::println);
    

增加了一系列的字串處理方法

// 判斷字串是否為空白
" ".isBlank(); // true
// 去除首尾空白 (與trim()存在區別,可去除所有的空格,包括中文空格)
" Javastack ".strip(); // "Javastack"
// 去除尾部空格
" Javastack ".stripTrailing(); // " Javastack"
// 去除首部空格
" Javastack ".stripLeading(); // "Javastack "
// 複製字串
"Java".repeat(3);// "JavaJavaJava"
// 行數統計
"A\nB\nC".lines().count(); // 3

// 讀取檔案
FileInputStream fis = new FileInputStream("src/com/atguigu/java11/StringTest.java");
byte[] buffer = new byte[fis.available()];
fis.read(buffer);
fis.close();
String string = new String(buffer);
string.lines().forEach(System.out::println);

Optional 加強

Opthonal 也增加了幾個非常酷的方法,現在可以很方便的將一個 Optional 轉換成一個 Stream, 或者當一個空 Optional 時給它一個替代的。

Optional.of("javastack").orElseThrow(); // javastack
Optional.of("javastack").stream().count(); // 1
Optional.ofNullable(null)
		.or(() -> Optional.of("javastack"))
		.get(); // javastack

改進的檔案API

InputStream 加強

InputStream 終於有了一個非常有用的方法:transferTo,可以用來將資料直接傳輸到 OutputStream,這是在處理原始資料流時非常常見的一種用法

var classLoader = ClassLoader.getSystemClassLoader();
var inputStream = classLoader.getResourceAsStream("javastack.txt");
var javastack = File.createTempFile("javastack2", "txt");
try (var outputStream = new FileOutputStream(javastack)) {
    // 把輸入流中的所有資料直接自動地複製到輸出流中
    inputStream.transferTo(outputStream);
}

移除的一些其他內容

移除項

  • 移除了com.sun.awt.AWTUtilities

  • 移除了sun.misc.Unsafe.defineClass,

  • 使用java.lang.invoke.MethodHandles.Lookup.defineClass來替代

  • 移除了Thread.destroy()以及 Thread.stop(Throwable)方法

  • 移除了sun.nio.ch.disableSystemWideOverlappingFileLockCheck、sun.locale.formatasdefault屬性

  • 移除了jdk.snmp模組

  • 移除了javafx,openjdk估計是從java10版本就移除了,oracle jdk10還尚未移除javafx,而java11版本則oracle的jdk版本也移除了javafx

  • 移除了Java Mission Control,從JDK中移除之後,需要自己單獨下載

  • 移除了這些Root Certificates :Baltimore Cybertrust Code Signing CA,SECOM ,AOL and Swisscom

廢棄項

  • -XX+AggressiveOpts選項

  • -XX:+UnlockCommercialFeatures

  • -XX:+LogCommercialFeatures選項也不再需要

標準Java非同步HTTP客戶端

這是 Java 9 開始引入的一個處理 HTTP 請求的的 HTTP Client API,該 API 支援同步和非同步,而在 Java 11 中已經為正式可用狀態,你可以在 java.net 包中找到這個 API。

var request = HttpRequest.newBuilder()
				.uri(URI.create("https://javastack.cn"))
				.GET()
				.build();
var client = HttpClient.newHttpClient();
// 同步
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
// 非同步
client.sendAsync(request, HttpResponse.BodyHandlers.ofString())
		.thenApply(HttpResponse::body)
		.thenAccept(System.out::println);

上面的 .GET() 可以省略,預設請求方式為 Get!

更簡化的編譯執行程式

JEP 330 : 增強java啟動器支援執行單個java原始碼檔案的程式.

注意點 :

  1. 執行原始檔中的第一個類, 第一個類必須包含主方法

  2. 並且不可以使用別原始檔中的自定義類, 本檔案中的自定義類是可以使用的.

一個命令編譯執行原始碼

// 編譯
> javac Javastack.java

// 執行
> java Javastack

在我們的認知裡面,要執行一個 Java 原始碼必須先編譯,再執行,兩步執行動作。而在未來的 Java 11 版本中,通過一個 java 命令就直接搞定了,如以下所示(並未產生.class檔案)。

> java Javastack.java

Unicode 10

Unicode 10 增加了8518個字元, 總計達到了136690個字元. 並且增加了4個指令碼.同時還有56個新的emoji表情符號.

Remove the JavaEE and CORBA Moudles

在java11中移除了不太使用的JavaEE模組和CORBA技術

CORBA來自於二十世紀九十年代,Oracle說,現在用CORBA開發現代Java應用程式已經沒有意義了,維護CORBA的成本已經超過了保留它帶來的好處。

但是刪除CORBA將使得那些依賴於JDK提供部分CORBA API的CORBA實現無法執行。目前還沒有第三方CORBA版本,也不確定是否會有第三方願意接手CORBA API的維護工作。

在java11中將java9標記廢棄的Java EE及CORBA模組移除掉,具體如下:

  1. xml相關的,
  • java.xml.ws,

  • java.xml.bind,

  • java.xml.ws,

  • java.xml.ws.annotation,

  • jdk.xml.bind,

  • jdk.xml.ws被移除,

只剩下java.xml,java.xml.crypto,jdk.xml.dom這幾個模組;

  1. java.corba,
  • java.se.ee,

  • java.activation,

  • java.transaction被移除,

但是java11新增一個java.transaction.xa模組

JEP : 335 : Deprecate the Nashorn JavaScript Engine

廢除Nashorn javascript引擎,在後續版本準備移除掉,有需要的可以考慮使用GraalVM

JEP : 336 : Deprecate the Pack200 Tools and API

Java5中帶了一個壓縮工具:Pack200,這個工具能對普通的jar檔案進行高效壓縮。其 實現原理是根據Java類特有的結構,合併常數 池,去掉無用資訊等來實現對java類的高效壓縮。由於是專門對Java類進行壓縮的,所以對普通檔案的壓縮和普通壓縮軟體沒有什麼兩樣,但是對於Jar 檔案卻能輕易達到10-40%的壓縮率。這在Java應用部署中很有用,尤其對於移動Java計算,能夠大大減小程式碼下載量。

Java5中還提供了這一技術的API介面,你可以將其嵌入到你的程式中使用。使用的方法很簡單,下面的短短几行程式碼即可以實現jar的壓縮和解壓:

// 壓縮
Packer packer=Pack200.newPacker(); 
OutputStream output=new BufferedOutputStream(new FileOutputStream(outfile)); 
packer.pack(new JarFile(jarFile), output); 
output.close(); 

// 解壓
Unpacker unpacker=Pack200.newUnpacker(); 
output=new JarOutputStream(new FileOutputStream(jarFile)); 
unpacker.unpack(pack200File, output); 
output.close(); 

Pack200的壓縮和解壓縮速度是比較快的,而且壓縮率也是很驚人的,在我是使用 的包4.46MB壓縮後成了1.44MB(0.322%),而且隨著包的越大壓縮率會根據明顯,據說如果jar包都是class類可以壓縮到1/9的大 小。其實JavaWebStart還有很多功能,例如可以按不同的jar包進行lazy下載和 單獨更新,設定可以根據jar中的類變動進行class粒度的下載。

但是在java11中廢除了pack200以及unpack200工具以及java.util.jar中的Pack200 API。因為Pack200主要是用來壓縮jar包的工具,由於網路下載速度的提升以及java9引入模組化系統之後不再依賴Pack200,因此這個版本將其移除掉。

新的Epsilon垃圾收集器

A NoOp Garbage Collector

JDK上對這個特性的描述是: 開發一個處理記憶體分配但不實現任何實際記憶體回收機制的GC, 一旦可用堆記憶體用完, JVM就會退出.

如果有System.gc()呼叫, 實際上什麼也不會發生(這種場景下和-XX:+DisableExplicitGC效果一樣), 因為沒有記憶體回收, 這個實現可能會警告使用者嘗試強制GC是徒勞.

用法 : -XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC

class Garbage {
	int n = (int)(Math.random() * 100);
    
	@Override
    public void finalize() {
		System.out.println(this + " : " + n + " is dying");
	}
}

public class EpsilonTest {
	public static void main(String[] args) {
		boolean flag = true;
		List<Garbage> list = new ArrayList<>();
		long count = 0;
		while (flag) {
			list.add(new Garbage());
			if (list.size() == 1000000 && count == 0) {
				list.clear();
				count++;
			}
		}
		System.out.println("程式結束");
	}
}

如果使用選項-XX:+UseEpsilonGC, 程式很快就因為堆空間不足而退出

使用這個選項的原因 :

提供完全被動的GC實現, 具有有限的分配限制和儘可能低的延遲開銷,但代價是記憶體佔用和記憶體吞吐量.

眾所周知, java實現可廣泛選擇高度可配置的GC實現. 各種可用的收集器最終滿足不同的需求, 即使它們的可配置性使它們的功能相交. 有時更容易維護單獨的實現, 而不是在現有GC實現上堆積另一個配置選項.

主要用途如下 :

  • 效能測試(它可以幫助過濾掉GC引起的效能假象)

  • 記憶體壓力測試(例如,知道測試用例 應該分配不超過1GB的記憶體, 我們可以使用-Xmx1g –XX:+UseEpsilonGC, 如果程式有問題, 則程式會崩潰)

  • 非常短的JOB任務(物件這種任務, 接受GC清理堆那都是浪費空間)

  • VM介面測試

  • Last-drop 延遲&吞吐改進

ZGC

這應該是JDK11最為矚目的特性, 沒有之一. 但是後面帶了Experimental, 說明這還不建議用到生產環境

ZGC, A Scalable Low-Latency Garbage Collector(Experimental)

ZGC, 這應該是JDK11最為矚目的特性, 沒有之一. 但是後面帶了Experimental, 說明這還不建議用到生產環境.

  • GC暫停時間不會超過10ms

  • 既能處理幾百兆的小堆, 也能處理幾個T的大堆(OMG)

  • 和G1相比, 應用吞吐能力不會下降超過15%

  • 為未來的GC功能和利用colord指標以及Load barriers優化奠定基礎

  • 初始只支援64位系統

ZGC的設計目標是:支援TB級記憶體容量,暫停時間低(<10ms),對整個程式吞吐量的影響小於15%。 將來還可以擴充套件實現機制,以支援不少令人興奮的功能,例如多層堆(即熱物件置於DRAM和冷物件置於NVMe快閃記憶體),或壓縮堆。

GC是java主要優勢之一. 然而, 當GC停頓太長, 就會開始影響應用的響應時間.消除或者減少GC停頓時長, java將對更廣泛的應用場景是一個更有吸引力的平臺. 此外, 現代系統中可用記憶體不斷增長,使用者和程式設計師希望JVM能夠以高效的方式充分利用這些記憶體, 並且無需長時間的GC暫停時間.

STW – stop the world

ZGC是一個併發, 基於region, 壓縮型的垃圾收集器, 只有root掃描階段會STW, 因此GC停頓時間不會隨著堆的增長和存活物件的增長而變長.

ZGC : avg 1.091ms max:1.681

G1 : avg 156.806 max:543.846

用法 : -XX:+UnlockExperimentalVMOptions –XX:+UseZGC, 因為ZGC還處於實驗階段, 所以需要通過JVM引數來解鎖這個特性

完全支援Linux容器(包括Docker)

許多執行在Java虛擬機器中的應用程式(包括Apache Spark和Kafka等資料服務以及傳統的企業應用程式)都可以在Docker容器中執行。但是在Docker容器中執行Java應用程式一直存在一個問題,那就是在容器中執行JVM程式在設定記憶體大小和CPU使用率後,會導致應用程式的效能下降。這是因為Java應用程式沒有意識到它正在容器中執行。隨著Java 10的釋出,這個問題總算得以解決,JVM現在可以識別由容器控制組(cgroups)設定的約束。可以在容器中使用記憶體和CPU約束來直接管理Java應用程式,其中包括:

  • 遵守容器中設定的記憶體限制

  • 在容器中設定可用的CPU

  • 在容器中設定CPU約束

Java 10的這個改進在Docker for Mac、Docker for Windows以及Docker Enterprise Edition等環境均有效。

容器的記憶體限制

在Java 9之前,JVM無法識別容器使用標誌設定的記憶體限制和CPU限制。而在Java 10中,記憶體限制會自動被識別並強制執行。

Java將伺服器類機定義為具有2個CPU和2GB記憶體,以及預設堆大小為實體記憶體的1/4。例如,Docker企業版安裝設定為2GB記憶體和4個CPU的環境,我們可以比較在這個Docker容器上執行Java 8和Java 10的區別。

首先,對於Java 8:

docker container run -it -m512 --entrypoint bash openjdk:latest
$ docker-java-home/bin/java -XX:+PrintFlagsFinal -version | grep MaxHeapSize
uintx MaxHeapSize = 524288000             
{product} {ergonomic}
openjdk version "1.8.0_162"

最大堆大小為512M或Docker EE安裝設定的2GB的1/4,而不是容器上設定的512M限制。

相比之下,在Java 10上執行相同的命令表明,容器中設定的記憶體限制與預期的128M非常接近:

docker container run -it -m512M --entrypoint bash openjdk:10-jdk
$ docker-java-home/bin/java -XX:+PrintFlagsFinal -version | grep MaxHeapSize
size_t MaxHeapSize = 134217728             
{product} {ergonomic}
openjdk version "10" 2018-03-20

設定可用的CPU

預設情況下,每個容器對主機CPU週期的訪問是無限的。可以設定各種約束來限制給定容器對主機CPU週期的訪問。Java 10可以識別這些限制:

docker container run -it --cpus 2 openjdk:10-jdk
jshell> Runtime.getRuntime().availableProcessors()
$1 ==> 2

分配給Docker EE的所有CPU會獲得相同比例的CPU週期。這個比例可以通過修改容器的CPU share權重來調整,而CPU share權重與其它所有執行在容器中的權重相關。此比例僅適用於正在執行的CPU密集型的程序。當某個容器中的任務空閒時,其他容器可以使用餘下的CPU時間。實際的CPU時間的數量取決於系統上執行的容器的數量。這些可以在Java 10中設定:

docker container run -it --cpu-shares 2048 openjdk:10-jdk
jshell> Runtime.getRuntime().availableProcessors()
$1 ==> 2

cpuset約束設定了哪些CPU允許在Java 10中執行。

docker run -it --cpuset-cpus="1,2,3" openjdk:10-jdk
jshell> Runtime.getRuntime().availableProcessors()
$1 ==> 3

分配記憶體和CPU

使用Java 10,可以使用容器設定來估算部署應用程式所需的記憶體和CPU的分配。我們假設已經確定了容器中執行的每個程序的記憶體堆和CPU需求,並設定了JAVA_OPTS配置。例如,如果有一個跨10個節點分佈的應用程式,其中五個節點每個需要512Mb的記憶體和1024個CPU-shares,另外五個節點每個需要256Mb和512個CPU-shares。

請注意,1個CPU share比例由1024表示。

對於記憶體,應用程式至少需要分配5Gb。

512Mb × 5 = 2.56Gb

256Mb × 5 = 1.28Gb

該應用程式需要8個CPU才能高效執行。

1024 x 5 = 5個CPU

512 x 5 = 3個CPU

最佳實踐是建議分析應用程式以確定執行在JVM中的每個程序實際需要多少記憶體和分配多少CPU。但是,Java 10消除了這種猜測,可以通過調整容器大小以防止Java應用程式出現記憶體不足的錯誤以及分配足夠的CPU來處理工作負載。

支援G1上的並行完全垃圾收集

對於 G1 GC,相比於 JDK 8,升級到 JDK 11 即可免費享受到:並行的 Full GC,快速的 CardTable 掃描,自適應的堆佔用比例調整(IHOP),在併發標記階段的型別解除安裝等等。這些都是針對 G1 的不斷增強,其中序列 Full GC 等甚至是曾經被廣泛詬病的短板,你會發現 GC 配置和調優在 JDK11 中越來越方便

JEP 331 : Low-Overhead Heap Profiling免費的低耗能飛行記錄儀和堆分析儀

通過JVMTI的SampledObjectAlloc回撥提供了一個開銷低的heap分析方式

提供一個低開銷的, 為了排錯java應用問題, 以及JVM問題的資料收集框架, 希望達到的目標如下 :

  • 提供用於生產和消費資料作為事件的API

  • 提供快取機制和二進位制資料格式

  • 允許事件配置和事件過濾

  • 提供OS,JVM和JDK庫的事件

JEP 329 : 實現RFC7539中指定的ChaCha20和Poly1305兩種加密演算法, 代替RC4

實現 RFC 7539的ChaCha20 and ChaCha20-Poly1305加密演算法

RFC7748定義的祕鑰協商方案更高效, 更安全. JDK增加兩個新的介面

XECPublicKey 和 XECPrivateKey

KeyPairGenerator kpg = KeyPairGenerator.getInstance(“XDH”);
NamedParameterSpec paramSpec = new NamedParameterSpec(“X25519”);
kpg.initialize(paramSpec);
KeyPair kp = kgp.generateKeyPair();

KeyFactory kf = KeyFactory.getInstance(“XDH”);
BigInteger u = new BigInteger(“xxx”);
XECPublicKeySpec pubSpec = new XECPublicKeySpec(paramSpec, u);
PublicKey pubKey = kf.generatePublic(pubSpec);

KeyAgreement ka = KeyAgreement.getInstance(“XDH”);
ka.init(kp.getPrivate());
ka.doPhase(pubKey, true);
byte[] secret = ka.generateSecret();

新的預設根許可權證書集

JEP 332最新的HTTPS安全協議TLS 1.3

實現TLS協議1.3版本, TLS允許客戶端和伺服器端通過網際網路以一種防止竊聽, 篡改以及訊息偽造的方式進行通訊

Java Flight Recorder

Flight Recorder源自飛機的黑盒子

Flight Recorder以前是商業版的特性,在java11當中開源出來,它可以匯出事件到檔案中,之後可以用Java Mission Control來分析。可以在應用啟動時配置java -XX:StartFlightRecording,或者在應用啟動之後,使用jcmd來錄製,比如

$ jcmd <pid> JFR.start
$ jcmd <pid> JFR.dump filename=recording.jfr
$ jcmd <pid> JFR.stop

是 Oracle 剛剛開源的強大特性。我們知道在生產系統進行不同角度的 Profiling,有各種工具、框架,但是能力範圍、可靠性、開銷等,大都差強人意,要麼能力不全面,要麼開銷太大,甚至不可靠可能導致 Java 應用程序宕機。

而 JFR 是一套整合進入 JDK、JVM 內部的事件機制框架,通過良好架構和設計的框架,硬體層面的極致優化,生產環境的廣泛驗證,它可以做到極致的可靠和低開銷。在 SPECjbb2015 等基準測試中,JFR 的效能開銷最大不超過 1%,所以,工程師可以基本沒有心理負擔地在大規模分散式的生產系統使用,這意味著,我們既可以隨時主動開啟 JFR 進行特定診斷,也可以讓系統長期執行 JFR,用以在複雜環境中進行“After-the-fact”分析。還需要苦惱重現隨機問題嗎?JFR 讓問題簡化了很多。

在保證低開銷的基礎上,JFR 提供的能力也令人眼前一亮,例如:我們無需 BCI 就可以進行 Object Allocation Profiling,終於不用擔心 BTrace 之類把程序搞掛了。對鎖競爭、阻塞、延遲,JVM GC、SafePoint 等領域,進行非常細粒度分析。甚至深入 JIT Compiler 內部,全面把握熱點方法、內聯、逆優化等等。JFR 提供了標準的 Java、C++ 等擴充套件 API,可以與各種層面的應用進行定製、整合,為複雜的企業應用棧或者複雜的分散式應用,提供 All-in-One 解決方案。而這一切都是內建在 JDK 和 JVM 內部的,並不需要額外的依賴,開箱即用。