精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Java22有你需要的新特性嗎?

開發 前端
向量API在Java中的獨特優勢在于其高效的并行計算能力、豐富的向量化指令集、跨平臺的數據并行算法支持以及對機器學習的特別優化。

從 2017 年開始,Java 版本更新策略從原來的每兩年一個新版本,改為每六個月一個新版本,以快速驗證新特性,推動 Java 的發展。讓我們跟隨 Java 的腳步,配合示例講解,看一看每個版本的新特性,本期是 Java22 的新特性。

概述

Java22 在 2024 年 3 月 19 日發布GA版本,共十二大特性:

  • JEP 423: G1垃圾回收器的區域固定(Region Pinning for G1)
  • JEP 447: super(...)前置語句(Statements before super(...),預覽)
  • JEP 454: 外部函數和內存API(Foreign Function & Memory API)
  • JEP 456: 未命名變量和模式(Unnamed Variables & Patterns)
  • JEP 457: 類文件API(Class-File API,預覽)
  • JEP 458: 啟動多文件源代碼程序(Launch Multi-File Source-Code Programs)
  • JEP 459: 字符串模板(String Templates,第二次預覽)
  • JEP 460: 向量API(Vector API,第七次孵化)
  • JEP 461: 流收集器(Stream Gatherers,預覽)
  • JEP 462: 結構化并發(Structured Concurrency,第二次預覽)
  • JEP 463: 隱式聲明的類和實例主方法(Implicitly Declared Classes and Instance Main Methods,第二次預覽)
  • JEP 464: 作用域值(Scoped Values,第二次預覽)

接下來我們一起看看這些特性。

JEP 423: G1垃圾回收器的區域固定(Region Pinning for G1)

JEP 423: G1垃圾回收器的區域固定旨在解決在使用Java本地接口(JNI)時遇到的垃圾回收(GC)延遲問題。

在使用JNI時,Java線程需要等待GC操作完成,這會導致應用程序的延遲增加。特別是在JNI關鍵區域,GC操作會被暫停,直到線程離開該區域。這種機制雖然可以確保GC的穩定性,但會顯著增加應用程序的延遲。

JEP 423通過引入區域固定機制來解決上述問題。具體來說,該特性允許在G1垃圾回收器中固定JNI代碼使用的內存區域,這樣即使在這些區域中存在GC操作,也不會影響到其他區域的垃圾回收。這通過以下方式實現:

  1. 區域計數器:在每個區域中維護一個計數器,用于記錄該區域中的臨界對象數量。當一個臨界對象被獲取時,計數器增加;當一個臨界對象被釋放時,計數器減少。
  2. 區域固定:在進行GC操作時,G1垃圾回收器會固定那些包含臨界對象的區域,確保這些區域在GC期間保持不變。這樣,即使線程處于JNI關鍵區域,垃圾回收也可以繼續進行,而不會被暫停。

JEP 423可以帶來顯著的性能改進:

  1. 減少延遲:通過允許在JNI關鍵區域期間繼續進行垃圾回收,減少了應用程序的延遲。
  2. 提高效率:Java線程無需等待GC操作完成,從而提高了開發人員的工作效率。
  3. 增強可預測性:該特性還增強了垃圾回收的可預測性,特別是在處理大對象時。

JEP 454: 外部函數和內存API(Foreign Function & Memory API)

FFM API是為了提供一個更安全、更高效的替代JNI(Java Native Interface)的API。JNI雖然允許Java程序調用本地代碼,但其使用復雜且容易引入安全問題。FFM API旨在簡化這一過程,提高開發者的生產力和體驗,同時增強性能、安全性和一致性。在Java22中正式發布。

FFM API通過有效地調用外部函數(即JVM外部的代碼)并安全地訪問外部內存(即不受JVM管理的內存),使Java程序能夠調用本機庫并處理本機數據,而不會出現脆弱性和危險。

FFM API經歷了多輪孵化和預覽,從Java17的JEP 412開始,經過Java18的JEP 419和Java19的JEP 424,再到Java20的JEP 434和Java21的JEP 442,最終在Java22中正式發布。這些改進包括:

  • API的集中管理:通過Arena接口集中管理本地段的生命周期。
  • 安全訪問外部內存:通過MemoryLayout和VarHandle操作和訪問結構化的外部內存。
  • 調用外部函數:通過Linker、FunctionDescriptor和SymbolLookup調用外部函數。

FFM API的主要收益包括:

  • 提高性能:通過直接調用本地函數和操作內存,提高了程序的執行效率。
  • 增強安全性:通過更嚴格的內存管理機制,減少了內存泄漏和安全漏洞的風險。
  • 提升開發體驗:簡化了與本地代碼的交互,使得開發者可以更專注于業務邏輯的實現。

我們看下官方示例:

// 1. 在C庫路徑上查找名為radixsort的外部函數
Linker linker = Linker.nativeLinker();
SymbolLookup stdlib = linker.defaultLookup();
final MemorySegment memorySegment = stdlib.find("radixsort").orElseThrow();
FunctionDescriptor descriptor = FunctionDescriptor.ofVoid(
        ValueLayout.ADDRESS,
        ValueLayout.JAVA_INT,
        ValueLayout.ADDRESS
);
MethodHandle radixsort = linker.downcallHandle(memorySegment, descriptor);

// 下面的代碼將使用這個外部函數對字符串進行排序

// 2. 分配棧上內存來存儲四個字符串
String[] javaStrings = {"mouse", "cat", "dog", "car"};
// 3. 使用try-with-resources來管理離堆內存的生命周期
try (Arena offHeap = Arena.ofConfined()) {
    // 4. 分配一段離堆內存來存儲四個指針
    MemorySegment pointers = offHeap.allocateArray(ValueLayout.ADDRESS, javaStrings.length);
    // 5. 將字符串從棧上內存復制到離堆內存
    for (int i = 0; i < javaStrings.length; i++) {
        MemorySegment cString = offHeap.allocateUtf8String(javaStrings[i]);
        pointers.setAtIndex(ValueLayout.ADDRESS, i, cString);
    }
    // 6. 通過調用外部函數對離堆數據進行排序
    radixsort.invoke(pointers, javaStrings.length, MemorySegment.NULL, '\0');
    // 7. 將排序后的字符串從離堆內存復制回棧上內存
    for (int i = 0; i < javaStrings.length; i++) {
        MemorySegment cString = pointers.getAtIndex(ValueLayout.ADDRESS, i);
        javaStrings[i] = cString.getUtf8String(0);
    }
} // 8. 所有離堆內存在此處被釋放

// 驗證排序結果
assert Arrays.equals(javaStrings, new String[] {"car", "cat", "dog", "mouse"});  // true

我們都知道,JNI也是可以調用外部代碼的,那FFM API相較于JNI的優勢在于:

  1. 更安全的內存訪問:FFM API 提供了一種更安全和受控的方式來與本地代碼交互,避免了JNI中常見的內存泄漏和數據損壞問題。
  2. 直接訪問本地內存:FFM API 允許Java程序直接訪問本地內存(即Java堆外的內存),這使得數據處理更加高效和靈活。
  3. 跨語言函數調用:FFM API 支持調用Java程序的外部函數,以與外部代碼和數據一起操作,而無需依賴JNI的復雜機制。
  4. 更高效的集成:FFM API 使得Java與C、C++等語言編寫的庫集成更加方便和高效,特別是在數據處理和機器學習等領域。
  5. 減少代碼復雜性:FFM API 提供了一種更簡潔的API,減少了JNI中復雜的代碼編寫和維護工作。
  6. 更廣泛的適用性:FFM API 不僅適用于簡單的函數調用,還可以處理復雜的內存管理任務,如堆外內存的管理。
  7. 提高性能:FFM API 通過高效的調用外部函數和安全地訪問外部內存,提高了程序的運行效率。

JEP 456: 未命名變量和模式(Unnamed Variables & Patterns)

JEP 456: 未命名變量和模式(Unnamed Variables & Patterns)是一個重要新特性,在Java21中預覽,在Java22中發布。旨在提高Java代碼的可讀性和可維護性。這一特性允許開發者在聲明變量或嵌套模式時使用下劃線字符(_)來表示未命名的變量或模式,從而簡化代碼并減少不必要的噪聲,提高代碼可讀性和可維護性。

比如:

public static void main(String[] args) {
    var _ = new Point(1, 2);
}

record Point(int x, int y) {
}

這個可以用在任何定義變量的地方,比如:

  • ... instanceof Point(_, int y)
  • r instanceof Point _
  • switch …… case Box(_)
  • for (Order _ : orders)
  • for (int i = 0, _ = sideEffect(); i < 10; i++)
  • try { ... } catch (Exception _) { ... } catch (Throwable _) { ... }

只要是這個不準備用,可以一律使用_代替。

JEP 458: 啟動多文件源代碼程序(Launch Multi-File Source-Code Programs)

這個功能主要是提升java命令的能力。比如我們手搓了兩個類:

// Prog.java
class Prog {
    public static void main(String[] args) { Helper.run(); }
}

// Helper.java
class Helper {
    static void run() { System.out.println("Hello!"); }
}

想要運行Prog的main方法,在JEP 458之前,我們需要先編譯Helper,然后通過-classpath指令加載編譯后的類,才能運行Prog。但是現在,java幫我們做了,我們直接使用java Prog.java就可以執行了。

很方便的一個功能,但是似乎好像大概看起來沒什么用,但是對于Java生態有深遠影響:

  1. 增強Java啟動器功能:JEP 458允許Java啟動器執行包含一個或多個文件的Java源碼應用程序。這一改進使得開發者可以更靈活地啟動和運行Java程序,特別是在需要處理多個源文件的復雜項目中,這一特性將大大提升開發效率和便利性。
  2. 促進Java生態系統的持續演進:JEP 458的引入是Java生態系統持續演進的一部分,與Java21的新特性和Quarkus的創新應用相輔相成。這些更新不僅提升了與現代Java生態系統的兼容性,還引入了領域模型驗證的改進和依賴于Java17的新特性,為開發者提供了更加穩定、高效的工具集。
  3. 推動Java項目的發展:JEP 458的新特性被歸類到四個主要的Java項目中,即Amber、Loom、Panama和Valhalla。這些項目旨在通過精巧的合并,孵化一系列組件,以便最終將其納入到JDK中。這表明JEP 458不僅是一個獨立的特性,而是Java生態系統中更廣泛技術演進的一部分,有助于推動整個Java生態系統的創新和發展。
  4. 簡化Java開發流程:通過簡化啟動多文件源碼程序的過程,JEP 458有助于簡化Java開發流程,使得開發者可以更加專注于業務邏輯的實現,而不是在啟動和運行程序上花費過多時間。

預覽功能

JEP 447: super(...)前置語句(Statements before super(...))

我們都知道,在子類的構造函數中,如果通過super(……)調用父類,在super之前是不允許有其他語句的。

大部分的時候這種限制都沒問題,但是有時候不太靈活。如果想在super之前加上一些子類特有邏輯,比如想統計下子類構造耗時,就得重寫一遍父類的實現。

除了有損靈活性,這種重寫的做法也會造成父子類之間的關系變得奇怪。假設父類是SDK中的一個類,SDK升級時在父類構造函數增加了一些邏輯,我們項目中是無法繼承這些邏輯的,某次需要升級SDK(比如低版本有安全風險),驗證不完整的情況下,就很容易出現bug。

在 JEP 447 中,允許在構造函數中不引用正在創建的實例的語句出現在顯式構造函數調用(如 super())之前。這一特性旨在為開發者提供更多的靈活性,允許在調用父類構造函數之前執行一些驗證或其他處理操作。

引入這一特性的主要動機是提高構造函數的靈活性和可讀性。通過允許在 super() 調用之前執行語句,開發者可以在構造函數中添加額外的邏輯,例如進行一些初始化檢查或執行一些特定的處理操作,而不必依賴于 super() 調用之后的代碼。

我們看下示例代碼:

public class PositiveBigInteger extends BigInteger {
    public PositiveBigInteger(long value) {
        if (value <= 0) {
            throw new IllegalArgumentException("non-positive value");
        }
        super(value);
    }
}

JEP 457: 類文件API(Class-File API,預覽)

Java中一直缺少官方的類文件操作API,想要操作class,我們需要借助第三方庫,比如javassist、ASM、ByteBuddy等。從2017年開始,Java每半年有一次升級,特性更新頻率增加,需要第三方庫同步更新,是比較困難的。

還有一個原因是Java中使用了ASM實現jar、jlink等工具,以及lambda表達式等。這就會出現一個問題,Java版本N依賴了ASM版本M,如果Java N中有類API,ASM M中是不會有的,只有Java N發布后,ASM升級到M+1才會有,Java想要使用ASM M+1,需要升級到Java N+1。是不是很顛,一個官方基礎語言,居然要依賴一個依賴這個語言的第三方工具。是可忍孰不可忍。

于是有了JEP 457,目標是提供一個準確、完整、高性能且遵循Java虛擬機規范定義的類文件格式的API,最終也會替換JDK內部的ASM副本。

因為當前還是預覽版,我們先簡單看下官方示例:

如果要實現下面這段:

void fooBar(boolean z, int x) {
    if (z)
        foo(x);
    else
        bar(x);
}

我們在ASM的寫法:

ClassWriter classWriter = ...;
MethodVisitor mv = classWriter.visitMethod(0, "fooBar", "(ZI)V", null, null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 1);
Label label1 = new Label();
mv.visitJumpInsn(IFEQ, label1);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ILOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, "Foo", "foo", "(I)V", false);
Label label2 = new Label();
mv.visitJumpInsn(GOTO, label2);
mv.visitLabel(label1);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ILOAD, 2);
mv.visitMethodInsn(INVOKEVIRTUAL, "Foo", "bar", "(I)V", false);
mv.visitLabel(label2);
mv.visitInsn(RETURN);
mv.visitEnd();

在JEP 457中的寫法:

ClassBuilder classBuilder = ...;
classBuilder.withMethod("fooBar", MethodTypeDesc.of(CD_void, CD_boolean, CD_int), flags,
                        methodBuilder -> methodBuilder.withCode(codeBuilder -> {
    Label label1 = codeBuilder.newLabel();
    Label label2 = codeBuilder.newLabel();
    codeBuilder.iload(1)
        .ifeq(label1)
        .aload(0)
        .iload(2)
        .invokevirtual(ClassDesc.of("Foo"), "foo", MethodTypeDesc.of(CD_void, CD_int))
        .goto_(label2)
        .labelBinding(label1)
        .aload(0)
        .iload(2)
        .invokevirtual(ClassDesc.of("Foo"), "bar", MethodTypeDesc.of(CD_void, CD_int))
        .labelBinding(label2);
        .return_();
});

還可以這樣寫:

CodeBuilder classBuilder = ...;
classBuilder.withMethod("fooBar", MethodTypeDesc.of(CD_void, CD_boolean, CD_int), flags,
                        methodBuilder -> methodBuilder.withCode(codeBuilder -> {
    codeBuilder.iload(codeBuilder.parameterSlot(0))
               .ifThenElse(
                   b1 -> b1.aload(codeBuilder.receiverSlot())
                           .iload(codeBuilder.parameterSlot(1))
                           .invokevirtual(ClassDesc.of("Foo"), "foo",
                                          MethodTypeDesc.of(CD_void, CD_int)),
                   b2 -> b2.aload(codeBuilder.receiverSlot())
                           .iload(codeBuilder.parameterSlot(1))
                           .invokevirtual(ClassDesc.of("Foo"), "bar",
                                          MethodTypeDesc.of(CD_void, CD_int))
               .return_();
});

寫法上比ASM更加優雅。

JEP 459: 字符串模板(String Templates,第二次預覽)

字符串模板是一個值得期待的功能,旨在增強Java編程語言。該特性通過將文字文本與嵌入式表達式和模板處理器結合,生成專門的結果,從而補充了Java現有的字符串文字和文本塊。

相對Java21中JEP 430,主要的優化改動包括:

  • 增強的表達式支持:允許在字符串模板中嵌入更復雜的表達式,這些表達式可以在運行時被計算和校驗。
  • 模板處理器:引入了模板處理器的概念,使得字符串模板可以更加靈活地處理不同的數據格式和結構。
  • 安全性提升:通過在運行時對嵌入的表達式進行校驗,提高了代碼的安全性。

字符串模板通過將文本和嵌入式表達式結合在一起,使得Java程序能夠以一種更加直觀和安全的方式構建字符串。與傳統的字符串拼接(使用+操作符)、StringBuilder或String.format 等方法相比,字符串模板提供了一種更加清晰和安全的字符串構建方式。特別是當字符串需要從用戶提供的值構建并傳遞給其他系統時(例如,構建數據庫查詢),使用字符串模板可以有效地驗證和轉換模板及其嵌入表達式的值,從而提高Java程序的安全性。

讓我們通過代碼看一下這個特性的魅力:

public static void main(String[] args) {
    // 拼裝變量
    String name = "看山";
    String info = STR. "My name is \{ name }" ;
    assert info.equals("My name is 看山");

    // 拼裝變量
    String firstName = "Howard";
    String lastName = "Liu";
    String fullName = STR. "\{ firstName } \{ lastName }" ;
    assert fullName.equals("Howard Liu");
    String sortName = STR. "\{ lastName }, \{ firstName }" ;
    assert sortName.equals("Liu, Howard");

    // 模板中調用方法
    String s2 = STR. "You have a \{ getOfferType() } waiting for you!" ;
    assert s2.equals("You have a gift waiting for you!");

    Request req = new Request("2017-07-19", "09:15", "https://www.howardliu.cn");
    // 模板中引用對象屬性
    String s3 = STR. "Access at \{ req.date } \{ req.time } from \{ req.address }" ;
    assert s3.equals("Access at 2017-07-19 09:15 from https://www.howardliu.cn");

    LocalTime now = LocalTime.now();
    String markTime = DateTimeFormatter
            .ofPattern("HH:mm:ss")
            .format(now);
    // 模板中調用方法
    String time = STR. "The time is \{
            // The java.time.format package is very useful
            DateTimeFormatter
                    .ofPattern("HH:mm:ss")
                    .format(now)
            } right now" ;
    assert time.equals("The time is " + markTime + " right now");

    // 模板嵌套模板
    String[] fruit = {"apples", "oranges", "peaches"};
    String s4 = STR. "\{ fruit[0] }, \{
            STR. "\{ fruit[1] }, \{ fruit[2] }"
            }" ;
    assert s4.equals("apples, oranges, peaches");

    // 模板與文本塊結合
    String title = "My Web Page";
    String text = "Hello, world";
    String html = STR. """
    <html>
      <head>
        <title>\{ title }</title>
      </head>
      <body>
        <p>\{ text }</p>
      </body>
    </html>
    """ ;
    assert html.equals("""
            <html>
              <head>
                <title>My Web Page</title>
              </head>
              <body>
                <p>Hello, world</p>
              </body>
            </html>
            """);

    // 帶格式化的字符串模板
    record Rectangle(String name, double width, double height) {
        double area() {
            return width * height;
        }
    }
    Rectangle[] zone = new Rectangle[] {
            new Rectangle("Alfa", 17.8, 31.4),
            new Rectangle("Bravo", 9.6, 12.4),
            new Rectangle("Charlie", 7.1, 11.23),
    };
    String table = FMT. """
        Description     Width    Height     Area
        %-12s\{ zone[0].name }  %7.2f\{ zone[0].width }  %7.2f\{ zone[0].height }     %7.2f\{ zone[0].area() }
        %-12s\{ zone[1].name }  %7.2f\{ zone[1].width }  %7.2f\{ zone[1].height }     %7.2f\{ zone[1].area() }
        %-12s\{ zone[2].name }  %7.2f\{ zone[2].width }  %7.2f\{ zone[2].height }     %7.2f\{ zone[2].area() }
        \{ " ".repeat(28) } Total %7.2f\{ zone[0].area() + zone[1].area() + zone[2].area() }
        """;
    assert table.equals("""
            Description     Width    Height     Area
            Alfa            17.80    31.40      558.92
            Bravo            9.60    12.40      119.04
            Charlie          7.10    11.23       79.73
                                         Total  757.69
            """);
}

public static String getOfferType() {
    return "gift";
}

record Request(String date, String time, String address) {
}

這個功能當前是第二次預覽,Java23的8.12版本中還沒有展示字符串模板的第三次預覽(JEP 465: String Templates),還不能確定什么時候可以正式用上。

JEP 461: 流收集器(Stream Gatherers,預覽)

JEP 461旨在增強Java Stream API、以支持自定義中間操作。這一特性允許開發者以更靈活和高效的方式處理數據流,從而提高流管道的表達能力和轉換數據的能力。

流收集器通過引入新的中間操作Stream::gather(Gatherer),允許開發者定義自定義的轉換實體(稱為Gatherer),從而對流中的元素進行轉換。這些轉換可以是一對一、一對多、多對一或多對多的轉換方式。此外,流收集器還支持保存以前遇到的元素,以便進行進一步的處理。

我們通過實例感受下這一特性的魅力:

public record WindowFixed<TR>(int windowSize) implements Gatherer<TR, ArrayList<TR>, List<TR>> {

    public static void main(String[] args) {
        var list = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9)
                .gather(new WindowFixed<>(3))
                .toList();
        // [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
        System.out.println(list);
    }

    public WindowFixed {
        // Validate input
        if (windowSize < 1) {
            throw new IllegalArgumentException("window size must be positive");
        }
    }

    @Override
    public Supplier<ArrayList<TR>> initializer() {
        // 創建一個 ArrayList 來保存當前打開的窗口
        return () -> new ArrayList<>(windowSize);
    }

    @Override
    public Integrator<ArrayList<TR>, TR, List<TR>> integrator() {
        // 集成器在每次消費元素時被調用
        return Gatherer.Integrator.ofGreedy((window, element, downstream) -> {

            // 將元素添加到當前打開的窗口
            window.add(element);

            // 直到達到所需的窗口大小,
            // 返回 true 表示希望繼續接收更多元素
            if (window.size() < windowSize) {
                return true;
            }

            // 當窗口已滿時,通過創建副本關閉窗口
            var result = new ArrayList<TR>(window);

            // 清空窗口以便開始新的窗口
            window.clear();

            // 將關閉的窗口發送到下游
            return downstream.push(result);

        });
    }

    // 由于此操作本質上是順序的,因此無法并行化,因此省略了合并器

    @Override
    public BiConsumer<ArrayList<TR>, Downstream<? super List<TR>>> finisher() {
        // 終結器在沒有更多元素傳遞時運行
        return (window, downstream) -> {
            // 如果下游仍然接受更多元素且當前打開的窗口非空,則將其副本發送到下游
            if (!downstream.isRejecting() && !window.isEmpty()) {
                downstream.push(new ArrayList<TR>(window));
                window.clear();
            }
        };
    }
}

該特性還是預覽版,等正式發布后再細說。

JEP 462: 結構化并發(Structured Concurrency,第二次預覽)

結構化并發API(Structured Concurrency API)旨在簡化多線程編程,通過引入一個API來處理在不同線程中運行的多個任務作為一個單一工作單元,從而簡化錯誤處理和取消操作,提高可靠性,并增強可觀測性。本次發布是第一次預覽。

結構化并發API提供了明確的語法結構來定義子任務的生命周期,并啟用一個運行時表示線程間的層次結構。這有助于實現錯誤傳播和取消以及并發程序的有意義觀察。

在JEP 462中,結構化并發API被進一步完善,使其更加易于使用和維護。主要的優化包括:

  • 工作單元概念:將一組相關任務視為一個工作單元,這樣可以簡化錯誤處理和取消操作。
  • 增強的可觀測性:通過API提供了更好的錯誤處理機制和任務狀態跟蹤功能,增強了代碼的可觀察性。
  • 虛擬線程支持:與Project Loom項目結合,支持在線程內和線程間共享不可變數據,這在使用大量虛擬線程時尤其有用。

Java使用異常處理機制來管理運行時錯誤和其他異常。當異常在代碼中產生時,如何被傳遞和處理的過程稱為異常傳播。

在結構化并發環境中,異常可以通過顯式地從當前環境中拋出并傳播到更大的環境中去處理。

在Java并發編程中,非受檢異常的處理是程序健壯性的重要組成部分。特別是對于非受檢異常的處理,這關系到程序在遇到錯誤時是否能夠優雅地繼續運行或者至少提供有意義的反饋。

try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
    var task1 = scope.fork(() -> {
        Thread.sleep(1000);
        return "Result from task 1";
    });

    var task2 = scope.fork(() -> {
        Thread.sleep(2000);
        return "Result from task 2";
    });

    scope.join();
    scope.throwIfFailed(RuntimeException::new);

    System.out.println(task1.get());
    System.out.println(task2.get());
} catch (Exception e) {
    e.printStackTrace();
}

在這個例子中,handle()方法使用StructuredTaskScope來并行執行兩個子任務:task1和task2。通過使用try-with-resources語句自動管理資源,并確保所有子任務都在try塊結束時正確完成或被取消。這種方式使得線程的生命周期和任務的邏輯結構緊密相關,提高了代碼的清晰度和錯誤處理的效率。使用 StructuredTaskScope 可以確保一些有價值的屬性:

  • 錯誤處理與短路:如果task1或task2子任務中的任何一個失敗,另一個如果尚未完成則會被取消。(這由 ShutdownOnFailure 實現的關閉策略來管理;還有其他策略可能)。
  • 取消傳播:如果在運行上面方法的線程在調用 join() 之前或之中被中斷,則線程在退出作用域時會自動取消兩個子任務。
  • 清晰性:設置子任務,等待它們完成或被取消,然后決定是成功(并處理已經完成的子任務的結果)還是失?。ㄗ尤蝿找呀浲瓿桑虼藳]有更多需要清理的)。
  • 可觀察性:線程轉儲清楚地顯示了任務層次結構,其中運行task1或task2的線程被顯示為作用域的子任務。

上面的示例能夠很好的解決我們的一個痛點,有兩個可并行的任務A和B,A+B才是完整結果,任何一個失敗,另外一個也不需要成功,結構化并發API就可以很容易的實現這個邏輯。

JEP 463: 隱式聲明的類和實例主方法(Implicitly Declared Classes and Instance Main Methods,第二次預覽)

無論學習哪門語言,第一課一定是打印Hello, World!,Java中的寫法是:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println ("Hello, World!");
    }
}

如果是第一次接觸,一定會有很多疑問,public干啥的,main方法的約定參數args是什么鬼?然后老師就說,這就是模板,照著抄就行,不這樣寫不運行。

JEP 445特性后,可以簡化為:

class HelloWorld {
    void main() {
        System.out.println ("Hello, World!");
    }
}

我們還可以這樣寫:

String greeting() { return "Hello, World!"; }

void main() {
    System.out.println(greeting());
}

main方法直接簡化為名字和括號,甚至連類也不需要顯性定義了。雖然看起來沒啥用,但是在JShell中使用,就比較友好了。

JEP 464: 作用域值(Scoped Values,第二次預覽)

作用域值(Scoped Values)在Java20孵化,在Java21第一次預覽,在Java22第二次預覽,旨在提供一種安全且高效的方法來共享數據,無需使用方法參數。這一特性允許在不使用方法參數的情況下,將數據安全地共享給方法,優先于線程局部變量,特別是在使用大量虛擬線程時。

在多線程環境中,作用域值可以在線程內和線程間共享不可變數據,例如從父線程向子線程傳遞數據,從而解決了在多線程應用中傳遞數據的問題。此外,作用域值提高了數據的安全性、不變性和封裝性,并且在多線程環境中使用事務、安全主體和其他形式的共享上下文的應用程序中表現尤為突出。

作用域值的主要特點:

  • 不可變性:作用域值是不可變的,這意味著一旦設置,其值就不能更改。這種不可變性減少了并發編程中意外副作用的風險。
  • 作用域生命周期:作用域值的生命周期僅限于 run 方法定義的作用域。一旦執行離開該作用域,作用域值將不再可訪問。
  • 繼承性:子線程會自動繼承父線程的作用域值,從而允許在線程邊界間無縫共享數據。

在這個功能之前,在多線程間傳遞數據,我們有兩種選擇:

  1. 方法參數:顯示參數傳遞;缺點是新增參數時修改聯動修改一系列方法,如果是框架或SDK層面的,無法做到向下兼容。
  2. ThreadLocal:在ThreadLocal保存當前線程變量。

使用過ThreadLocal的都清楚,ThreadLocal會有三大問題。

  1. 無約束的可變性:每個線程局部變量都是可變的。任何可以調用線程局部變量的get方法的代碼都可以隨時調用該變量的set方法。即使線程局部變量中的對象是不可變的,每個字段都被聲明為final,情況仍然如此。ThreadLocal API允許這樣做,以便支持一個完全通用的通信模型,在該模型中,數據可以在方法之間以任何方向流動。這可能會導致數據流混亂,導致程序難以分辨哪個方法更新共享狀態以及以何種順序進行。
  2. 無界生存期:一旦通過set方法設置了一個線程局部變量的副本,該值就會在該線程的生存期內保留,或者直到該線程中的代碼調用remove方法。我們有時候會忘記調用remove,如果使用線程池,在一個任務中設置的線程局部變量的值如果不清除,可能會意外泄漏到無關的任務中,導致危險的安全漏洞(比如人員SSO)。對于依賴于線程局部變量的無約束可變性的程序來說,可能沒有明確的點可以保證線程調用remove是安全的,可能會導致內存泄漏,因為每個線程的數據在退出之前都不會被垃圾回收。
  3. 昂貴的繼承:當使用大量線程時,線程局部變量的開銷可能會更糟糕,因為父線程的線程局部變量可以被子線程繼承。(事實上,線程局部變量并不是某個特定線程的本地變量。)當開發人員選擇創建一個繼承了線程局部變量的子線程時,該子線程必須為之前在父線程中寫入的每個線程局部變量分配存儲空間。這可能會顯著增加內存占用。子線程不能共享父線程使用的存儲,因為ThreadLocal API要求更改線程的線程局部變量副本在其他線程中不可見。這也會有另一個隱藏的問題,子線程沒有辦法向父線程set數據。

作用域值可以有效解決上面提到的問題,而且寫起來更加優雅。

我們一起看下作用域值的使用:

// 聲明一個作用域值用于存儲用戶名
public final static ScopedValue<String> USERNAME = ScopedValue.newInstance();

private static final Runnable printUsername = () ->
        System.out.println(Thread.currentThread().threadId() + " 用戶名是 " + USERNAME.get());

public static void main(String[] args) throws Exception {
    // 將用戶名 "Bob" 綁定到作用域并執行 Runnable
    ScopedValue.where(USERNAME, "Bob").run(() -> {
        printUsername.run();
        new Thread(printUsername).start();
    });

    // 將用戶名 "Chris" 綁定到另一個作用域并執行 Runnable
    ScopedValue.where(USERNAME, "Chris").run(() -> {
        printUsername.run();
        new Thread(() -> {
            new Thread(printUsername).start();
            printUsername.run();
        }).start();
    });

    // 檢查在任何作用域外 USERNAME 是否被綁定
    System.out.println("用戶名是否被綁定: " + USERNAME.isBound());
}

寫起來干凈利索,而且功能更強。

孵化功能

JEP 460: 向量API(Vector API,第七次孵化)

向量API的功能是提供一個表達向量計算的API,旨在通過引入向量計算API來提高Java應用程序的性能。這一API允許開發者在支持的CPU架構上可靠地編譯為最佳向量指令,從而實現比等效的標量計算更高的性能。這些計算在運行時可靠地編譯成支持的CPU架構上的最優向量指令,從而實現比等效標量計算更優的性能。

下面這個是官方給的示例:

// 標量計算示例
void scalarComputation(float[] a, float[] b, float[] c) {
    for (int i = 0; i < a.length ; i++) {
        c[i] = (a[i] * a[i] + b[i] * b[i]) * -1.0f;
    }
}

// 使用向量API的向量計算示例
static final VectorSpecies<Float> SPECIES = FloatVector.SPECIES_PREFERRED;

void vectorComputation(float[] a, float[] b, float[] c) {
    int i = 0;
    int upperBound = SPECIES.loopBound(a.length);
    for (; i < upperBound; i += SPECIES.length()) {
        // FloatVector va, vb, vc;
        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;
    }
}

向量API在Java中的獨特優勢在于其高效的并行計算能力、豐富的向量化指令集、跨平臺的數據并行算法支持以及對機器學習的特別優化。


責任編輯:武曉燕 來源: 看山的小屋
相關推薦

2020-11-20 07:54:22

Java 特性語句

2019-05-20 13:45:15

MySQL新特性數據庫

2023-08-14 09:59:31

Debian操作系統

2021-12-27 18:27:18

GoTryLockJava

2021-06-23 09:46:16

Python 3.10結構模式管理器

2024-03-21 16:49:01

Java22版本開發

2013-02-25 14:02:07

RubyWeb

2021-03-30 14:50:41

前端TypeScript 命令

2012-03-24 21:02:41

iOS

2019-08-26 18:45:59

RedisRedis4.0數據庫

2015-06-29 09:40:10

Rails新特性

2017-09-16 15:55:54

ChromeJavaScriptAndroid

2014-08-21 10:34:11

Java 9Java

2021-01-14 10:38:41

Java枚舉工具

2021-02-22 11:51:15

Java開發代碼

2018-02-25 22:37:21

應用開關Java

2012-11-22 11:35:15

打印機

2010-12-21 11:31:09

2020-09-17 13:10:54

Java1編程語言新特性

2014-07-15 14:48:26

Java8
點贊
收藏

51CTO技術棧公眾號

国产成人亚洲综合无码| 91九色蝌蚪成人| 免费看的黄色网| 高清不卡一区| 亚洲第一久久影院| 日韩高清av电影| aaaa一级片| 久久免费高清| 欧美成人一区在线| 这里只有久久精品| 亚洲不卡视频| 欧美特级限制片免费在线观看| 欧美一级中文字幕| 国产毛片在线| 成人禁用看黄a在线| 国产精品美女视频网站| 亚洲国产精一区二区三区性色| 欧美日韩一二三四| 亚洲国产第一页| 中文字幕中文在线| 奇米777日韩| 亚洲国产欧美日韩另类综合| 亚洲欧洲三级| 欧美日本韩国一区二区| 国产成人精品免费看| 国产精品揄拍500视频| 天天综合天天干| 精品白丝av| 欧美精品在线播放| 国产又粗又猛又爽又黄的视频四季| 久久porn| 欧美哺乳videos| 亚洲五月激情网| 精品123区| 色婷婷国产精品综合在线观看| 国产精品视频网站在线观看| 浪潮av一区| 国产精品久久久久久久岛一牛影视| 精品免费视频123区| 亚洲第一页综合| 国产福利一区二区三区| 成人字幕网zmw| 亚洲天堂aaa| 青青草精品视频| 国产精品激情自拍| 无码人妻aⅴ一区二区三区有奶水 无码免费一区二区三区 | 99成人在线| 久久久这里只有精品视频| 69av视频在线| 欧美激情1区2区| 久热精品视频在线观看| 免费国产羞羞网站美图| 亚洲成人tv| 久久综合亚洲社区| 538精品在线观看| 亚洲精品在线观看91| 久久精品电影网| 国产真实乱在线更新| 欧美一区二区三区另类| 久久综合国产精品台湾中文娱乐网 | www.丝袜精品| 亚洲国产成人久久| 人妻精品久久久久中文字幕| 久久99性xxx老妇胖精品| 亚洲男人天堂久| 国产精品久久久视频| 99国产精品一区二区| 欧美大片va欧美在线播放| 国产真人真事毛片| 亚洲免费网站| 国产精品视频专区| 国产情侣一区二区| 成人黄色小视频在线观看| 九九九九久久久久| 国产三级视频在线播放线观看| 国产午夜久久久久| 手机看片日韩国产| 国产在线观看www| 色婷婷av一区二区三区软件 | 国产精品资源网站| 国产九区一区在线| 国产永久免费高清在线观看视频| 欧美国产日韩一二三区| 热这里只有精品| 国产精品久久久久久福利| 一区二区三区波多野结衣在线观看 | 亚洲综合在线小说| 午夜在线视频免费| 国产精品久久久久久久久免费丝袜 | 欧美日韩xx| 亚洲国产精品视频| 黄色av免费在线播放| 欧美成人精品一级| 亚洲精品第一页| 国产午夜精品理论片在线| 亚洲国产mv| 国产精品亚发布| 色婷婷综合视频| 国产精品不卡视频| 国产xxxxx在线观看| 99国内精品久久久久| 亚洲男人天堂网站| 国产小视频在线观看免费| 秋霞影院一区二区| 国产在线精品一区二区三区| 最近高清中文在线字幕在线观看| 亚洲国产精品一区二区尤物区| 亚洲无吗一区二区三区| 加勒比色老久久爱综合网| 中文字幕免费精品一区高清| 免费在线观看黄网站| 精品亚洲aⅴ乱码一区二区三区| 精品久久久久久一区| 国内精品久久久久国产| 日本道免费精品一区二区三区| 欧美69精品久久久久久不卡| 日韩久久电影| 日本国产欧美一区二区三区| 亚洲第一精品网站| 亚洲婷婷综合色高清在线| 欧美伦理视频在线观看| 秋霞蜜臀av久久电影网免费| 欧美成人免费va影院高清| 中文字幕一区二区三区免费看| 99久久精品99国产精品| 被灌满精子的波多野结衣| 国产精品亚洲欧美一级在线| 国产一区二区三区在线观看视频| 国产成人免费观看视频| 国产成人小视频| av不卡在线免费观看| 欧美黑粗硬大| 中文字幕少妇一区二区三区| www五月天com| 久久综合色一综合色88| 蜜桃传媒一区二区三区| 久久香蕉网站| 国内免费精品永久在线视频| 丰满人妻一区二区三区免费| 亚洲精品成人a在线观看| 不卡的在线视频| 久久国产影院| 成人激情视频在线观看| 欧美18一19xxx性| 欧美欧美欧美欧美| 日本精品在线免费观看| 国产综合久久久久久鬼色| 亚洲综合首页| 爱情电影网av一区二区| 久久的精品视频| 亚洲AV无码精品国产| 亚洲尤物视频在线| 黄色性视频网站| 亚洲少妇自拍| 日韩亚洲欧美精品| 日韩电影精品| 欧美精品亚州精品| 天天干视频在线| 欧美日韩一二三四五区| 久久久视频6r| 国产一区二区三区黄视频 | 日韩av资源在线播放| 二区视频在线观看| 久久久亚洲高清| 欧美伦理片在线看| 一区二区在线| 国产欧美日韩亚洲| 肉色欧美久久久久久久免费看| 国产一区二区三区久久精品| 亚洲无码精品国产| 亚洲激情成人在线| 国产精品福利导航| 青青草国产精品97视觉盛宴| 裸体裸乳免费看| www国产精品| 国产精品v片在线观看不卡| 91在线直播| 日韩免费福利电影在线观看| 精品在线播放视频| 国产精品不卡在线| 国产精品久久无码| 蜜桃视频在线观看一区二区| 日韩中文字幕亚洲精品欧美| 青草久久视频| 成人免费观看a| 黄色在线网站噜噜噜| 中文字幕av一区| 国产91麻豆视频| 欧洲精品中文字幕| 国产精选第一页| 中文字幕精品—区二区四季| 亚洲AV成人精品| 日本中文字幕一区二区有限公司| 欧美交换配乱吟粗大25p| 你懂的一区二区三区| 亚洲自拍欧美色图| 成人爱爱网址| 色与欲影视天天看综合网| 国产一二三区在线| 精品国产3级a| 国产原创中文av| 欧美性猛交视频| 国产亚洲精品久久久久久打不开| 国产女人aaa级久久久级| 国产a级片视频| 久久99精品久久久久久动态图| 乱妇乱女熟妇熟女网站| 91精品高清| 色噜噜一区二区| 日韩大片在线免费观看| 99久久精品免费看国产四区| 国产精品色婷婷视频| 国产大片在线免费观看 | 理论片中文字幕| 欧美日韩国产首页在线观看| 黄色一级片免费在线观看| 亚洲日本在线a| 黄色三级生活片| 99re66热这里只有精品3直播 | 国产精品日韩成人| 粉嫩av蜜桃av蜜臀av| 成人性视频免费网站| 中文字幕 欧美日韩| 日韩成人一区二区三区在线观看| 国产精品国产亚洲精品看不卡| 综合久久精品| 中国黄色录像片| 天天综合一区| 樱花www成人免费视频| 成人激情开心网| 日韩福利影院| 残酷重口调教一区二区| 亚洲精品影视在线观看| 日韩hmxxxx| 高清一区二区| 成人在线视频福利| 99久久久国产精品免费调教网站| 91高潮精品免费porn| 阿v视频在线| 97视频在线观看播放| 欧美日韩国产观看视频| 91精品国产91久久久久久不卡| 草美女在线观看| 国内成人精品视频| 92久久精品| 91精品国产高清久久久久久91| 亚洲v.com| 国产精国产精品| 日本精品在线一区| 91精品久久久久久久久久久久久久 | 91小视频在线播放| 激情五月婷婷综合网| 伊人免费视频二| 岛国一区二区在线观看| 成人午夜精品无码区| 99re视频精品| 无码人妻aⅴ一区二区三区69岛| 国产日韩欧美精品一区| 青青草华人在线视频| 亚洲欧美区自拍先锋| 国产主播在线观看| 欧美日韩午夜激情| 99re热视频| 日韩视频在线永久播放| 欧日韩在线视频| 亚洲日本欧美中文幕| 五月婷婷在线观看| 欧美激情手机在线视频| 涩涩视频网站在线观看| 国产精品丝袜高跟| 999在线精品| 欧美久久久久久久| 97视频精品| 欧美一级片免费播放| 日日摸夜夜添夜夜添亚洲女人| 五月婷婷丁香色| 国产成人a级片| 国产色视频一区二区三区qq号| 国产欧美日本一区视频| 久久精品一区二区三区四区五区| 亚洲一区二区三区中文字幕| 国产成人亚洲精品自产在线| 欧美日韩一区二区在线观看视频| 精品人妻无码一区二区三区蜜桃一| 亚洲国产成人久久综合一区| jizz在线观看中文| 欧美激情精品在线| ww久久综合久中文字幕| 国产v亚洲v天堂无码| 精品高清久久| 亚洲理论电影在线观看| 日韩 欧美一区二区三区| 美国黄色一级视频| 国产精品午夜在线观看| 国产午夜精品无码| 欧美日韩国产一区| 欧美在线观看在线观看| 久久视频在线免费观看| 成人性生活视频| 99在线视频免费观看| 成人无号精品一区二区三区| 日本午夜激情视频| 狠狠色丁香婷婷综合| 国产肥白大熟妇bbbb视频| 亚洲午夜日本在线观看| 一级黄色片视频| 亚洲人成电影在线| jizzjizz中国精品麻豆| 91视频国产高清| 日韩国产一区二区三区| 黄色片久久久久| www.日韩精品| 男人与禽猛交狂配| 欧美日韩亚洲综合一区二区三区| 四虎影视在线观看2413| 欧美激情视频在线免费观看 欧美视频免费一 | 成人av动漫在线观看| 黄色影院一级片| 国产99久久久久久免费看农村| 视频国产一区二区| 欧美自拍偷拍一区| 外国精品视频在线观看 | 天堂av免费看| 美国毛片一区二区三区| 女人十八毛片嫩草av| 一本到一区二区三区| 欧美中文在线| 日本午夜在线亚洲.国产| 欧美亚洲tv| 黄色国产一级视频| 成人美女视频在线看| 久久黄色小视频| 日韩欧美一区二区久久婷婷| 国产美女福利在线| 91热福利电影| 亚洲人体av| 在线观看一区二区三区视频| 中文字幕在线观看不卡视频| 在线播放国产一区| 中文字幕欧美日韩精品| 欧美美女被草| 天堂av在线中文| 国产成人午夜精品影院观看视频 | 国产精品.com| 国产主播精品| 在线观看国产免费视频| 精品成人久久av| 日韩a级作爱片一二三区免费观看| 91精品国产免费久久久久久| 美女亚洲一区| 日本久久久久久久久久久久| 国产精品久久看| 97免费观看视频| 色综合男人天堂| 日韩高清三区| 91av在线免费播放| 国产精品美女一区二区在线观看| 中文字幕免费播放| 两个人的视频www国产精品| 日本一区二区三区播放| 国产一二三在线视频| 久久久影院官网| 中文字幕av影视| 久久久国产成人精品| 波多野结衣一区二区三区免费视频| 日韩少妇内射免费播放| 国产亲近乱来精品视频| 国产农村老头老太视频| 久久久久国产视频| 国产精品亚洲片在线播放| 天堂av在线8| 亚洲va天堂va国产va久| 国产精品久久久久一区二区国产 | 免费成人三级| 热久久精品免费视频| 亚洲欧美偷拍三级| 无码国产精品一区二区免费16| 国产精品成久久久久三级| 婷婷激情图片久久| 日韩av无码一区二区三区不卡| 色美美综合视频| 中文在线观看免费| 久久久一本精品99久久精品66| 另类小说视频一区二区| 豆国产97在线 | 亚洲| 国产一区二区三区中文| 97青娱国产盛宴精品视频| 久久久久免费精品| 一区二区三区精品| sese在线视频| 久久本道综合色狠狠五月| 精品一区二区三区免费播放| 国产a∨精品一区二区三区仙踪林| 中日韩美女免费视频网址在线观看 | 日韩视频在线观看一区| 久久九九国产精品怡红院| 日韩最新在线| 久久黄色一级视频| 欧美性色黄大片| 九色porny丨首页入口在线|