日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

生产升级JDK 17 必读手册

發布時間:2023/12/31 windows 31 coder
生活随笔 收集整理的這篇文章主要介紹了 生产升级JDK 17 必读手册 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文點這里,查看更多優質文章

DK 17 在 2021 年 9 月 14 號正式發布了!根據發布的規劃,這次發布的 JDK 17 是一個長期維護的版本(LTS)。

Java 17 提供了數千個性能穩定性安全性更新,以及 14 個 JEP(JDK 增強提案),進一步改進了 Java 語言和平臺,以幫助開發人員提高工作效率。

JDK 17 包括新的語言增強、庫更新、對新 Apple (Mx CPU)計算機的支持、舊功能的刪除和棄用,并努力確保今天編寫的 Java 代碼在未來的 JDK 版本中繼續工作而不會發生變化。它還提供語言功能預覽和孵化 API,以收集 Java 社區的反饋

語言特性增強

密封的類和接口(正式版)

封閉類可以是封閉類和或者封閉接口,用來增強 Java 編程語言,防止其他類或接口擴展或實現它們。這個特性由Java 15的預覽版本晉升為正式版本。

  • 密封的類和接口解釋和應用

因為我們引入了sealed classinterfaces,這些class或者interfaces只允許被指定的類或者interface進行擴展和實現。

使用修飾符sealed,您可以將一個類聲明為密封類。密封的類使用reserved關鍵字permits列出可以直接擴展它的類。子類可以是最終的,非密封的或密封的。

之前我們的代碼是這樣的。

public class Person { } //人
 
class Teacher extends Person { }//教師
 
class Worker extends Person { } ?//工人
 
class Student extends Person{ } //學生

但是我們現在要限制 Person類 只能被這三個類繼承,不能被其他類繼承,需要這么做。

// 添加sealed修飾符,permits后面跟上只能被繼承的子類名稱
public sealed class Person permits Teacher, Worker, Student{ } //人
 
// 子類可以被修飾為 final
final class Teacher extends Person { }//教師
 
// 子類可以被修飾為 non-sealed,此時 Worker類就成了普通類,誰都可以繼承它
non-sealed class Worker extends Person { } ?//工人
// 任何類都可以繼承Worker
class AnyClass extends Worker{}
 
//子類可以被修飾為 sealed,同上
sealed class Student extends Person permits MiddleSchoolStudent,GraduateStudent{ } //學生
 
 
final class MiddleSchoolStudent extends Student { } ?//中學生
 
final class GraduateStudent extends Student { } ?//研究生

很強很實用的一個特性,可以限制類的層次結構。

  • 補充:它是由Amber項目孵化而來(會經歷兩輪以上預覽版本)

什么是Amber項目?

Amber 項目的目標是探索和孵化更小的、以生產力為導向的 Java 語言功能,這些功能已被 OpenJDK JEP 流程接受為候選 JEP。本項目由 Compiler Group 贊助。 大多數 Amber 功能在成為 Java 平臺的正式部分之前至少要經過兩輪預覽。對于給定的功能,每輪預覽和最終標準化都有單獨的 JEP。此頁面僅鏈接到某個功能的最新 JEP。此類 JEP 可能會酌情鏈接到該功能的早期 JEP。

工具庫的更新

JEP 306:恢復始終嚴格的浮點語義

Java 編程語言和 Java 虛擬機最初只有嚴格的浮點語義。從 Java 1.2 開始,默認情況下允許在這些嚴格語義中進行微小的變化,以適應當時硬件架構的限制。這些差異不再有幫助或必要,因此已被 JEP 306 刪除。

JEP 356:增強的偽隨機數生成器

為偽隨機數生成器 (PRNG) 提供新的接口類型和實現。這一變化提高了不同 PRNG 的互操作性,并使得根據需求請求算法變得容易,而不是硬編碼特定的實現。簡單而言只需要理解如下三個問題: @pdai

JDK 17之前如何生成隨機數?

  1. Random 類

典型的使用如下,隨機一個int值

// random int
new Random().nextInt();
?
/**
 * description 獲取指定位數的隨機數
 *
 * @param length 1
 * @return java.lang.String
 */
public static String getRandomString(int length) {
 ? ?String base = "abcdefghijklmnopqrstuvwxyz0123456789";
 ? ?Random random = new Random();
 ? ?StringBuilder sb = new StringBuilder();
 ? ?for (int i = 0; i < length; i++) {
 ? ? ? ?int number = random.nextInt(base.length());
 ? ? ? ?sb.append(base.charAt(number));
 ?  }
 ? ?return sb.toString();
}
  1. ThreadLocalRandom 類

提供線程間獨立的隨機序列。它只有一個實例,多個線程用到這個實例,也會在線程內部各自更新狀態。它同時也是 Random 的子類,不過它幾乎把所有 Random 的方法又實現了一遍。

/**
 * nextInt(bound) returns 0 <= value < bound; repeated calls produce at
 * least two distinct results
 */
public void testNextIntBounded() {
 ? ?// sample bound space across prime number increments
 ? ?for (int bound = 2; bound < MAX_INT_BOUND; bound += 524959) {
 ? ? ? ?int f = ThreadLocalRandom.current().nextInt(bound);
 ? ? ? ?assertTrue(0 <= f && f < bound);
 ? ? ? ?int i = 0;
 ? ? ? ?int j;
 ? ? ? ?while (i < NCALLS &&
 ? ? ? ? ? ? ? (j = ThreadLocalRandom.current().nextInt(bound)) == f) {
 ? ? ? ? ? ?assertTrue(0 <= j && j < bound);
 ? ? ? ? ? ?++i;
 ? ? ?  }
 ? ? ? ?assertTrue(i < NCALLS);
 ?  }
}
  1. SplittableRandom 類

非線程安全,但可以 fork 的隨機序列實現,適用于拆分子任務的場景。

/**
 * Repeated calls to nextLong produce at least two distinct results
 */
public void testNextLong() {
 ? ?SplittableRandom sr = new SplittableRandom();
 ? ?long f = sr.nextLong();
 ? ?int i = 0;
 ? ?while (i < NCALLS && sr.nextLong() == f)
 ? ? ? ?++i;
 ? ?assertTrue(i < NCALLS);
}

為什么需要增強?

  1. 上述幾個類實現代碼質量和接口抽象不佳
  2. 缺少常見的偽隨機算法
  3. 自定義擴展隨機數的算法只能自己去實現,缺少統一的接口

增強后是什么樣的

代碼的優化自不必說,我們就看下新增了哪些常見的偽隨機算法

如何使用這個呢?可以使用RandomGenerator

RandomGenerator g = RandomGenerator.of("L64X128MixRandom");

JEP 382:新的macOS渲染管道

使用 Apple Metal API 為 macOS 實現 Java 2D 管道。新管道將減少 JDK 對已棄用的 Apple OpenGL API 的依賴。

目前默認情況下,這是禁用的,因此渲染仍然使用OpenGL API;要啟用metal,應用程序應通過設置系統屬性指定其使用:

-Dsun.java2d.metal=true

Metal或OpenGL的使用對應用程序是透明的,因為這是內部實現的區別,對Java API沒有影響。Metal管道需要macOS 10.14.x或更高版本。在早期版本上設置它的嘗試將被忽略。

新的平臺支持

JEP 391:支持macOS AArch64

將 JDK 移植到 macOS/AArch64 平臺。該端口將允許 Java 應用程序在新的基于 Arm 64 的 Apple Silicon 計算機上本地運行。

舊功能的刪除和棄用

JEP 398:棄用 Applet API

所有網絡瀏覽器供應商要么已取消對 Java 瀏覽器插件的支持,要么已宣布計劃這樣做。 Applet API 已于 2017 年 9 月在 Java 9 中棄用,但并未移除。

JEP 407:刪除 RMI 激活

刪除遠程方法調用 (RMI) 激活機制,同時保留 RMI 的其余部分。

JEP 410:刪除實驗性 AOT 和 JIT 編譯器

實驗性的基于 Java 的提前 (AOT) 和即時 (JIT) 編譯器是實驗性功能,并未得到廣泛采用。作為可選,它們已經從 JDK 16 中刪除。這個 JEP 從 JDK 源代碼中刪除了這些組件。

JEP 411:棄用安全管理器以進行刪除

安全管理器可以追溯到 Java 1.0。多年來,它一直不是保護客戶端 Java 代碼的主要方法,也很少用于保護服務器端代碼。在未來的版本中將其刪除將消除重大的維護負擔,并使 Java 平臺能夠向前發展。

新功能的預覽和孵化API

JEP 406:新增switch模式匹配(預覽版)

允許針對多個模式測試表達式,每個模式都有特定的操作,以便可以簡潔安全地表達復雜的面向數據的查詢。

JEP 412:外部函數和內存api (第一輪孵化)

改進了 JDK 14 和 JDK 15 中引入的孵化 API,使 Java 程序能夠與 Java 運行時之外的代碼和數據進行互操作。通過有效地調用外部函數(即 JVM 之外的代碼)和安全地訪問外部內存,這些 API 使 Java 程序能夠調用本地庫和處理本地數據,而不會像 Java 本地接口 (JNI) 那樣脆弱和復雜。這些 API 正在*項目中開發,旨在改善 Java 和非 Java 代碼之間的交互。

JEP 414:Vector API(第二輪孵化)

如下內容來源于https://xie.infoq.cn/article/8304c894c4e38318d38ceb116,作者是九叔

AVX(Advanced Vector Extensions,高級向量擴展)實際上是 x86-64 處理器上的一套 SIMD(Single Instruction Multiple Data,單指令多數據流)指令集,相對于 SISD(Single instruction, Single dat,單指令流但數據流)而言,SIMD 非常適用于 CPU 密集型場景,因為向量計算允許在同一個 CPU 時鐘周期內對多組數據批量進行數據運算,執行性能非常高效,甚至從某種程度上來看,向量運算似乎更像是一種并行任務,而非像標量計算那樣,在同一個 CPU 時鐘周期內僅允許執行一組數據運算,存在嚴重的執行效率低下問題。

隨著 Java16 的正式來臨,開發人員可以在程序中使用 Vector API 來實現各種復雜的向量計算,由 JIT 編譯器 Server Compiler(C2)在運行期將其編譯為對應的底層 AVX 指令執行。當然,在講解如何使用 Vector API 之前,我們首先來看一個簡單的標量計算程序。示例:

void scalarComputation() {
 ? ?var a = new float[10000000];
 ? ?var b = new float[10000000];
 ? ?// 省略數組a和b的賦值操作
 ? ?var c = new float[10000000];
 ? ?for (int i = 0; i < a.length; i++) {
 ? ? ? ?c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
 ?  }
}

在上述程序示例中,循環體內每次只能執行一組浮點運算,總共需要執行約 1000 萬次才能夠獲得最終的運算結果,可想而知,這樣的執行效率必然低效。值得慶幸的是,從 Java6 的時代開始,Java 的設計者們就在 HotSpot 虛擬機中引入了一種被稱之為 SuperWord 的自動向量優化算法,該算法缺省會將循環體內的標量計算自動優化為向量計算,以此來提升數據運算時的執行效率。當然,我們可以通過虛擬機參數-XX:-UseSuperWord來顯式關閉這項優化(從實際測試結果來看,如果不開啟自動向量優化,存在約 20%~22%之間的性能下降)。

在此大家需要注意,盡管 HotSpot 缺省支持自動向量優化,但局限性仍然非常明顯,首先,JIT 編譯器 Server Compiler(C2)僅僅只會對循環體內的代碼塊做向量優化,并且這樣的優化也是極不可靠的;其次,對于一些復雜的向量運算,SuperWord 則顯得無能為力。因此,在一些特定場景下(比如:機器學習,線性代數,密碼學等),建議大家還是盡可能使用 Java16 為大家提供的 Vector API 來實現復雜的向量計算。示例:

// 定義256bit的向量浮點運算
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_256;
void vectorComputation(float[] a, float[] b, float[] c) {
 ? ?var i = 0;
 ? ?var upperBound = SPECIES.loopBound(a.length);
 ? ?for (; i < upperBound; i += SPECIES.length()) {
 ? ? ? ?var va = FloatVector.fromArray(SPECIES, a, i);
 ? ? ? ?var vb = FloatVector.fromArray(SPECIES, b, i);
 ? ? ? ?var vc = va.mul(va).
 ? ? ? ? ? ? ? ?add(vb.mul(vb)).
 ? ? ? ? ? ? ? ?neg();
 ? ? ? ?vc.intoArray(c, i);
 ?  }
 ? ?for (; i < a.length; i++) {
 ? ? ? ?c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
 ?  }
}

值得注意的是,Vector API 包含在 jdk.incubator.vector 模塊中,程序中如果需要使用 Vector API 則需要在 module-info.java 文件中引入該模塊。:

module java16.test{
 ? ?requires jdk.incubator.vector;
}

JEP 389:外部鏈接器 API(孵化器)

該孵化器 API 提供了靜態類型、純 Java 訪問原生代碼的特性,該 API 將大大簡化綁定原生庫的原本復雜且容易出錯的過程。Java 1.1 就已通過 Java 原生接口(JNI)支持了原生方法調用,但并不好用。Java 開發人員應該能夠為特定任務綁定特定的原生庫。它還提供了外來函數支持,而無需任何中間的 JNI 粘合代碼。

JEP 393:外部存儲器訪問 API(第三次孵化)

在 Java 14 和 Java 15 中作為孵化器 API 引入的這個 API 使 Java 程序能夠安全有效地對各種外部存儲器(例如本機存儲器、持久性存儲器、托管堆存儲器等)進行操作。它提供了外部鏈接器 API 的基礎。

如下內容來源于https://xie.infoq.cn/article/8304c894c4e38318d38ceb116,作者是九叔

在實際的開發過程中,絕大多數的開發人員基本都不會直接與堆外內存打交道,但這并不代表你從未接觸過堆外內存,像大家經常使用的諸如:RocketMQ、MapDB 等中間件產品底層實現都是基于堆外存儲的,換句話說,我們幾乎每天都在間接與堆外內存打交道。那么究竟為什么需要使用到堆外內存呢?簡單來說,主要是出于以下 3 個方面的考慮:

  • 減少 GC 次數和降低 Stop-the-world 時間;
  • 可以擴展和使用更大的內存空間;
  • 可以省去物理內存和堆內存之間的數據復制步驟。

在 Java14 之前,如果開發人員想要操作堆外內存,通常的做法就是使用 ByteBuffer 或者 Unsafe,甚至是 JNI 等方式,但無論使用哪一種方式,均無法同時有效解決安全性和高效性等 2 個問題,并且,堆外內存的釋放也是一個令人頭痛的問題。以 DirectByteBuffer 為例,該對象僅僅只是一個引用,其背后還關聯著一大段堆外內存,由于 DirectByteBuffer 對象實例仍然是存儲在堆空間內,只有當 DirectByteBuffer 對象被 GC 回收時,其背后的堆外內存才會被進一步釋放。

在此大家需要注意,程序中通過 ByteBuffer.allocateDirect()方法來申請物理內存資源所耗費的成本遠遠高于直接在 on-heap 中的操作,而且實際開發過程中還需要考慮數據結構如何設計、序列化/反序列化如何支撐等諸多難題,所以與其使用語法層面的 API 倒不如直接使用 MapDB 等開源產品來得更實惠。

如今,在堆外內存領域,我們似乎又多了一個選擇,從 Java14 開始,Java 的設計者們在語法層面為大家帶來了嶄新的 Memory Access API,極大程度上簡化了開發難度,并得以有效的解決了安全性和高效性等 2 個核心問題。示例:

// 獲取內存訪問var句柄
var handle = MemoryHandles.varHandle(char.class,
 ? ? ? ?ByteOrder.nativeOrder());
// 申請200字節的堆外內存
try (MemorySegment segment = MemorySegment.allocateNative(200)) {
 ? ?for (int i = 0; i < 25; i++) {
 ? ? ? ?handle.set(segment, i << 2, (char) (i + 1 + 64));
 ? ? ? ?System.out.println(handle.get(segment, i << 2));
 ?  }
}

關于堆外內存段的釋放,Memory Access API 提供有顯式和隱式 2 種方式,開發人員除了可以在程序中通過 MemorySegment 的 close()方法來顯式釋放所申請的內存資源外,還可以注冊 Cleaner 清理器來實現資源的隱式釋放,后者會在 GC 確定目標內存段不再可訪問時,釋放與之關聯的堆外內存資源。

參考文章

  • https://www.oracle.com/news/announcement/oracle-releases-java-17-2021-09-14/

  • https://openjdk.java.net/projects/amber/

  • https://pdai.tech/md/java/java8up/java17.html

  • https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/random/package-summary.html


總結

以上是生活随笔為你收集整理的生产升级JDK 17 必读手册的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。