精品欧美一区二区三区在线观看 _久久久久国色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丨九色丨丰满| 日韩午夜免费| 久久综合伊人77777蜜臀| 国产又黄又粗又猛又爽的视频 | 国产精品久久久久久久久久久久久久久久久久 | 亚洲ww精品| 欧美网站在线观看| 欧美少妇一区二区三区| 国外av在线| 成人h精品动漫一区二区三区| 国产精品久久视频| 国产成人精品一区二三区| 小处雏高清一区二区三区| 亚洲女人被黑人巨大进入| 伊人久久久久久久久| 日韩av电影资源网| 色综合久久综合| 日韩极品视频在线观看| 国产原创视频在线观看| 日本一区二区综合亚洲| 精品麻豆av| 亚洲国产精品国自产拍久久| 久久成人免费网| 国产成人在线一区二区| 日本在线播放视频| 日韩视频一区| 午夜精品理论片| 精品在线免费观看视频| 欧美91视频| 久久综合国产精品台湾中文娱乐网| 亚洲午夜精品久久久久久高潮| 亚洲精品小区久久久久久| 亚洲成人网在线| 四虎精品一区二区| 国产精品天天看天天狠| 日韩免费看网站| 亚洲精品一二三四| 日韩精品中文字幕吗一区二区| 欧美一区二区在线免费观看| 在线观看日本www| 91精品国产一区二区在线观看| 欧美三级一区二区| 亚洲77777| 欧美xxxx性| 91麻豆精品国产自产在线| 国产成人美女视频| 久久99精品久久久野外观看| 欧美一区二区高清| 性折磨bdsm欧美激情另类| 亚洲啊v在线免费视频| 日韩精品一区二区三区中文不卡| 日本成人在线免费| 美女视频亚洲色图| 亚洲欧美综合另类中字| 国产免费无遮挡吸奶头视频| 欧美色网址大全| 一区二区三区无码高清视频| 超碰人人人人人人人| 久久久久久久久久久久久久久久久久| 久久精品国产一区| 国产精品99re| 国产美女精品| 国产精品自拍视频| 精品人妻伦一区二区三区久久| 成人白浆超碰人人人人| 欧美裸体网站| 成人午夜在线影视| 亚洲第一激情av| 亚洲男人天堂色| 国产精品99久久免费| 亚洲韩国青草视频| 午夜时刻免费入口| 午夜天堂精品久久久久| 欧美一级视频一区二区| 中文字幕乱码一区二区| 国产·精品毛片| 欧美日韩无遮挡| 国产二区三区在线| 日韩欧美一区二区三区久久| 手机免费av片| 综合亚洲自拍| 久久国产精品99国产精| 久久国产黄色片| 国产精品原创巨作av| 精品一区国产| 91亚洲天堂| 色婷婷综合久久久中文一区二区 | 日韩一区二区视频在线| 精一区二区三区| 久久久久一区二区三区| 欧美日韩在线看片| 日韩欧美精品免费在线| 两女双腿交缠激烈磨豆腐| 亚洲人和日本人hd| 欧美日韩国产成人高清视频| 免费看av在线| 91麻豆蜜桃一区二区三区| 一区二区三区四区五区精品| 久热在线观看视频| 7777精品伊人久久久大香线蕉超级流畅 | 成人免费性视频| 久久亚洲精品中文字幕| 亚洲精品永久免费| 麻豆成人在线视频| 捆绑调教美女网站视频一区| 美女被啪啪一区二区| 女囚岛在线观看| 欧美日韩电影在线播放| 中文字幕第20页| 亚洲免费观看| 国产91免费视频| av在线免费网址| 欧美日韩中文字幕精品| 精品人妻一区二区三区香蕉| 尤物在线精品| 99在线视频首页| 黄色成人在线| 7777精品久久久大香线蕉| 亚洲AV无码成人精品区明星换面| 一本一本久久| 国产偷久久久精品专区| 免费污视频在线| 日韩精品一区二区三区在线观看 | 国产黄a三级三级三级av在线看| 在线观看不卡视频| 一女三黑人理论片在线 | 日本精品免费在线观看| 国内精品国产成人国产三级粉色| 欧美裸身视频免费观看| 国产精品探花视频| 亚洲美女屁股眼交3| 中文字幕在线观看日| 国产精品久久久久久影院8一贰佰 国产精品久久久久久麻豆一区软件 | 久久久久成人精品无码中文字幕| 亚洲视频精品| 国产伦精品一区二区三毛| 欧美hdxxx| 亚洲国产精品女人久久久| 99免费在线观看| av资源站一区| 激情五月开心婷婷| 国产不卡av一区二区| 国产福利视频一区| 91精彩视频在线观看| 欧美日韩美女一区二区| 顶臀精品视频www| 国产精品一卡二| 成人免费观看在线| 欧美日韩大片免费观看| 日本高清+成人网在线观看| 国产在线一二| 欧美日韩一区二区三区在线看| 国产探花视频在线| 国产在线看一区| 毛片av在线播放| 日本精品影院| 国产精品视频免费观看www| 国产美女福利在线| 欧美精品一区二区三区蜜桃| 天天操中文字幕| 中文乱码免费一区二区| www.51色.com| 夜夜嗨网站十八久久| 欧洲视频一区二区三区| 日韩综合久久| 国内精品久久久久久影视8| 牛牛影视精品影视| 欧美另类videos死尸| 国产精品不卡av| 国产午夜三级一区二区三| www.五月天色| 性8sex亚洲区入口| 宅男在线精品国产免费观看| 久久香蕉网站| 国产日产久久高清欧美一区| missav|免费高清av在线看| 亚洲欧美激情另类校园| 国产精品一区二区人人爽| 精品久久久免费| 久久久精品少妇| 91在线观看高清| 亚洲欧美日韩精品一区| 亚洲人人精品| 亚洲第一页在线视频| 亚洲免费福利一区| 99re在线| 欧美视频精品| 欧美性在线观看| 毛片在线不卡| 国产午夜精品全部视频播放| 亚洲狼人综合网| 欧美三区免费完整视频在线观看| 亚洲免费激情视频| 亚洲精品中文字幕乱码三区 | 欧美自拍偷拍| 国产一区二区三区四区hd| 天堂久久一区| 日韩av免费网站| 99热99re6国产在线播放| x99av成人免费| 国产精品久久久久久久龚玥菲| 精品国产网站在线观看| 91theporn国产在线观看| 欧美视频中文字幕在线| 久久国产在线视频| 亚洲色图丝袜美腿| 国产视频不卡在线| 91亚洲精品久久久蜜桃| 欧美极品jizzhd欧美仙踪林| 国产乱色国产精品免费视频| 日韩精品视频一二三| 视频一区二区欧美| 久久综合九色综合88i| 欧美性久久久| 国产精品igao激情视频| 欧美成人激情| 亚洲一区三区视频在线观看| 国产成人黄色| 欧美亚洲免费在线| 亚洲瘦老头同性70tv| 久久国产精品久久精品国产| 国产精品视频3p| 国语精品中文字幕| 国内视频在线精品| 国产在线精品一区二区三区》| 亚洲三级av| 99国产在线视频| 亚洲一区二区三区日本久久九| 亚洲一区二区三区乱码aⅴ| 99久久久国产| 91久久精品一区| 玖玖玖视频精品| 亚洲最大av在线| 这里视频有精品| 国产精品成人一区二区三区| 丁香婷婷成人| 精品国产一区二区三区久久久久久 | av片在线观看网站| 色综合男人天堂| 青春草在线免费视频| 97热精品视频官网| 中文字幕在线官网| 国产精品h片在线播放| 精品欧美日韩精品| 成人在线播放av| 一区视频网站| 久久66热这里只有精品| 中文字幕伦av一区二区邻居| 亚洲高清视频在线观看| 国产精品福利在线观看播放| 草草草视频在线观看| 日韩一级网站| 亚欧美在线观看| 国产精品亚洲视频| 日韩www视频| 国产亚洲欧美日韩日本| 顶级黑人搡bbw搡bbbb搡| 一区二区三区四区在线播放| 亚洲精品77777| 欧美日韩一区不卡| 亚洲精品无amm毛片| 亚洲欧美日韩一区二区三区在线| av中文字幕一区二区三区| 久久的精品视频| 激情国产在线| 成人福利网站在线观看| 国产无遮挡裸体免费久久| 日韩精品第一页| 午夜国产精品视频免费体验区| 日本国产在线播放| 男人操女人的视频在线观看欧美| av影片在线播放| 亚洲国产岛国毛片在线| 精国产品一区二区三区a片| 91久久免费观看| 国产免费一区二区三区最新不卡| 亚洲国产福利在线| 日韩黄色影院| 69久久夜色精品国产7777| 亚洲成人1区| 欧美精品与人动性物交免费看| 综合国产在线| 热久久精品国产| 成人综合在线网站| 亚洲天堂精品一区| 欧美日韩国内自拍| 99久久精品免费看国产交换| 亚洲精品美女网站| 麻豆传媒在线完整视频| 清纯唯美日韩制服另类| 日韩中文一区二区| 亚洲一卡二卡区| 午夜一区不卡| 久久久久久久久久久影视| 国产日产欧美精品一区二区三区| 久久老司机精品视频| 欧美日韩夫妻久久| 东热在线免费视频| 5278欧美一区二区三区| 日韩一区二区三区色| 亚洲国产日韩综合一区| 久久激情视频| 亚洲一区二区三区四区五区六区 | 99热久久这里只有精品| 久久99热99| 国产成人免费观看网站| 精品人伦一区二区三区蜜桃网站| 国产v片在线观看| 爱福利视频一区| 国产精品66| 五月天国产一区| 日本中文字幕一区| 玖玖爱在线观看| 偷拍日韩校园综合在线| 六月婷婷综合网| 欧美超级免费视 在线| 青草综合视频| 亚洲精品中字| 日韩va欧美va亚洲va久久| 高潮毛片无遮挡| 黑人巨大精品欧美一区二区一视频| 亚洲AV无码国产精品午夜字幕 | 先锋欧美三级| 人偷久久久久久久偷女厕| 久久久久国产一区二区| 国产免费看av| 色欧美乱欧美15图片| 四虎精品在永久在线观看| 国产91精品久久久久| 牛牛精品成人免费视频| 成人网站免费观看入口| 99久久99久久免费精品蜜臀| 日韩av女优在线观看| 日韩电影中文字幕| 在线日韩影院| 日本一区二区三区四区高清视频| 天堂一区二区在线免费观看| 无码人妻精品一区二区中文| 一本一本大道香蕉久在线精品| 男人天堂资源在线| 国产女人18毛片水18精品| 国产精品88久久久久久| 成人亚洲免费视频| 一区二区三区四区高清精品免费观看| 性一交一乱一伧老太| 久久久久女教师免费一区| 欧美18免费视频| 日本精品www| 国产精品久久国产精麻豆99网站 | yy6080久久伦理一区二区| 亚洲午夜精品久久久中文影院av| 久久成人免费网| 久久综合亚洲色hezyo国产| 亚洲精品国产精品乱码不99按摩 | 三级黄色免费观看| 日韩欧美一区二区三区在线| 2019中文字幕在线电影免费| 免费久久久一本精品久久区| 奇米影视一区二区三区小说| 男人与禽猛交狂配| 亚洲高清免费观看高清完整版| 欧美艳星kaydenkross| 在线亚洲美日韩| av资源站一区| 夜夜躁狠狠躁日日躁av| 欧美激情精品久久久久久| 丝袜av一区| 日日干夜夜操s8| 香蕉av福利精品导航| av免费观看一区二区| 岛国视频一区免费观看| 模特精品在线| 久久久久国产精品夜夜夜夜夜| 亚洲欧美另类中文字幕| 精品国模一区二区三区欧美 | 美女视频一区二区| 国产在线视频在线观看| 中日韩午夜理伦电影免费| 欧美成人精品午夜一区二区| 黄色片久久久久| 亚洲一区二区三区中文字幕 | 国产精品乱人伦中文| 乱精品一区字幕二区| 国产精品一区久久久| 亚洲尤物精选| 久久精品www| 少妇av一区二区三区| 久久大胆人体视频|