---
# System prepended metadata

title: 2023 java conference
tags: [conference]

---

# 2023 java conference

## 2023 java conference 聽講順序

09:25–09:35 報到
### 演講

| 時間 | 地點 | 主題 |
| -------- | -------- | -------- |
| 09:40 ~ 10:25	  | 401     | 深入淺出 Java 21 功能    |
| 10:40 ~ 11:25	  | 402CD   | Redis 快取設計漫談    |
| 11:40 ~ 12:25	  | 401     | 🇬🇧 🎞️ Jakarta EE and MicroProfile: Open Cloud-Native Java APIs for All|
| 12:25 ~ 13:25   |         | Lunch and Break|
| 13:25 ~ 13:40   | 203     | 面試的內容(x)|
| 13:45 ~ 14:00	  | 303     | java串接line pay付款  (x)  |
| 14:10 ~ 14:55	  | 203     | Create your library    |
| 15:05 ~ 15:50   | 402cd   | http
| 15:50 ~ 16:20   |         |Tea Time|
| 16:20 ~ 17:05   | 401     |Refactoring to Serverless|
| 17:15 ~ 18:00   | 401     |  Virtual Threads|


## 第一場 : 深入淺出介紹了jAVA 21 的新功能


參考 :  https://cyberjos.blog/java/seminar/jcconf-2023-head-first-java-21/



## 第二場 : Redis 快取設計漫談


## Lunch and Break 吃便當

## Tea Time


## 最後一場 : Virtual Threads
大綱分別是
● Java 對應多執⾏緒的歷史

● 為什麼要 Virtual Threads

● 如何使⽤ Virtual Threads

● ⼀些要注意的細節

● Java 21 後


## Virtual Threads 是甚麼呢
- ⼀種輕量級由 JVM 管理的執⾏緒
    - 與既有的⼀對⼀對應 Platform Thread 不同
    - 使⽤⽅式基本上跟現在的 Thread 沒有差異 ,原本使用 Thread API 的既有程式碼能在最小的 改動下採用虛擬執行緒
    - • 繼承 Thread 的輕量級執行緒，可大幅減少撰 寫、維護和監控高吞吐並行程式的工作量
• 用 thread-per-request 風格撰寫的服務器應用 程式能以接近最佳化的硬體使用率來進行擴容
• 原本使用 Thread API 的既有程式碼能在最小的 改動下採用虛擬執行緒
• 與既有的 JDK 工具整合，使其易於使用、除錯 和量測

- 目的 : 為了因應現在後端⾼ Throughput 的情境
    - 現在的後端開發很多都是⾼ I/O 的情況，
    - 使⽤⼀個執⾏緒對應⼀個請求變成⼀種浪費.



## Thread 的利⽤⽅法
```
new Thread(() -> {
   try {
       Thread.sleep(1000L);
   } catch (InterruptedException e) {
       Thread.currentThread().interrupt();
   }
}).start();

```


## Thread 的利⽤⽅法

```
Thread.ofPlatform().start(() -> {
   try {
       Thread.sleep(1000L);
   } catch (InterruptedException e) {
       Thread.currentThread().interrupt();
   }
});
```

## Virtual Threads 的利⽤⽅法

```
Thread.ofVirtual().start(() -> {
   try {
       Thread.sleep(1000L);
   } catch (InterruptedException e) {
       Thread.currentThread().interrupt();
   }
});
```

## Thread 的利⽤⽅法

```
ExecutorService executorService =
       Executors.newFixedThreadPool(16);
public void foo(Request request) {
  executorService.submit(() -> {
    try {
      Thread.sleep(1000L);
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
    }
  });
  ...
}

```

## Virtual Threads 的利⽤⽅法
```
ExecutorService executorService = Executors.newVirtualThreadPerTaskExecutor();
public void foo(Request request) { executorService.submit(() -> {
try { Thread.sleep(1000L);
} catch (InterruptedException e) { Thread.currentThread().interrupt();
}
});
...
}

```


## Virtual Threads 的利用方法

- 通常後端來說，不太需要自己建立 Thread，只 要框架本身提供的處理要求的 Thread 為 Virtual Thread，那就可以用一個 request 一個 Thread 的方式寫跟程式邏輯
- 以前需要使用 Thread Pool 在背後執行的部分 ，可以利用 Executors 的 newVirtualThreadPerTaskExecutor

# 記憶體的使用量
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { IntStream.range(0, 8_000).forEach(i -> executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(10));
return i; }));
}
// 補圖
Thread (reserved=78389KB, committed=78389KB)

//使用一班的
try (var executor = Executors.newCachedThreadPool()) { IntStream.range(0, 8_000).forEach(i -> executor.submit(() -> {
Thread.sleep(Duration.ofSeconds(10));
return i; }));
}

// 補圖
Thread (reserved=16561256KB, committed=16561256KB)

## Thread 的後端開發

最早典型的後端會有 Thread Pool，對每個存取 一對一處理
![image.png](https://hackmd.io/_uploads/S1zqK21Qa.png)


多數後端開發都會有存取資料庫或其他外部API後 等待I/O
![image.png](https://hackmd.io/_uploads/BJupF2ymp.png)

同時間來的大量的請求時，會利用到多個執行緒
![image.png](https://hackmd.io/_uploads/B1gbchkQT.png)

超過預期的請求，只能讓它們等或是開更多執行緒
![image.png](https://hackmd.io/_uploads/rykQq2km6.png)


## 後端程式常有的情況
 程式中業務邏輯在整個要求中佔的比例不高
○ 資料庫存取約10ms
○ 存取其他後端約10~100ms
○ 實際上在取得資料後的處理花費非常小，所
以一個執行緒基本上只會佔用一點 CPU 處 理邏輯

## 一請求對應一執行緒的問題
典型的環境我們通常會開幾百到幾千執行緒也 不會遇到太大問題
○ Platform Thread 大概需要 1~2MB 左右， 建立大概要 milliseconds 等級
● 沒有限制執行緒而請求增加到達一個程度 ○ java.lang.OutOfMemory
○ Context switch 的成本
● 多數 Server 會使用 Thread Pool 限制上限 ○ 超過預期的要求會產生大量的 Timeout

## 多數 Server 會使用 Thread Pool 限制上限 ○ 超過預期的要求會產生大量的 Timeout
 為了讓 CPU 不閒置，使用像 CompletableFuture、WebFlux 以及 RxJava 之類的函示庫，搭配非同步 I/O 及少量的 執行緒來改進效能
 
原本的指令式程式碼

List<Item> getRanking(String country) {
String rankingType = api.getRankingType("JP"); List<String> rankingIds =
searchClient.getRanking(rankingType); return rankingIds.stream()
.map(dao::getItem) .collect(Collectors.toList());
}
    
利用 CompletableFuture
    CompletableFuture<List<Item>> getRanking(String country) { return api.getRankingType("JP").thenCompose(rankingType -> {
return searchClient.getRanking(rankingType); }).thenCompose(rankingIds -> {
final List<CompletableFuture<Item>> itemFutures = rankingIds.stream().map(dao::getItem).toList();
return CompletableFuture .allOf(itemFutures.toArray(
new CompletableFuture[0])) .thenApply(ignored ->
itemFutures.stream().map(CompletableFuture::join) .toList());
}); 
    
非同步程式的問題
    
● 一使用類似模式，所有方法基本上都得利用一 樣模式撰寫
● 程式丟出 Exception 時， stack trace 只有執行 時的 Thread 資訊，非常難除錯
● 無法利用簡單的 try catch 錯誤處理
    
Stack trace 示意
    
![image.png](https://hackmd.io/_uploads/Syzbs21XT.png)

## Virtual Threads
    如果執行緒能變得非常輕量?就能像以前一樣 用指令式的方式撰寫
○ 錯誤處理和除錯都變得容易
○ 提高 Throughput
● 多輕量?有辦法建立幾十到百萬以上的執行緒
○ 數百 Bytes 的 metadata
○ Stack 的資料放在 Heap
○ Context switch 快(ns 等級)
    
    建立 Virtual Thread 不會馬上佔用 Platform Threadﬁ›
![image.png](https://hackmd.io/_uploads/rk98sny76.png)


Virtual Threads
    可以透過 -Djdk.virtualThreadScheduler.parallelism 設定 carrier thread 的數量，預設為 processor 的數量
    
List<Item> getRanking(String country) {
String rankingType = api.getRankingType("JP"); List<String> rankingIds =
searchClient.getRanking(rankingType); return rankingIds.stream()
.map(dao::getItem) .collect(Collectors.toList());
}

一些要注意的地方
    
## 對 Virtual Thread 的誤解
● 轉換成 Virtual Thread 並不會變更快
○ 導入的理由是為了更高的 Throughput
○ 對於被執行的 Task，帶來的 overhead 是變
多的
○ 幾乎只有 CPU 運算為主的工作，就可能不
適合利用它
● 不要重複利用 Virtual Thread，一個 Task 就是
一個 Thread
> Executors#newVirtualThreadPerTaskExecutor

## Thread pinning
    ● 以下狀況下 Virtual Threads 無法在 blocking 時 unmount
○ 執行 synchronized 方法和區塊
○ 執行 native
● 盡量避免使用 synchronized
○ 如果 synchronized 的區塊不多且佔用時間 不⻑，可以測量看看不一定要急著改
○ 需要的話可以利用如 java.util.concurrent.lock.ReentrantLock
    
## Thread pinning
    
可以利用 JFR 或是 -Djdk.tracePinnedThreads=full 來找出有問題 的地方
    
## ThreadLocal
    ThreadLocal 通常用在兩種狀況 ○ 用來傳遞 context 物件
■ 例如 Spring 的 transaction 和 RequestContextHolder
○ 當作較重的資源的 cached/pool
■ 例如 Jackson、OpenTelemetry
■ 如果有幾十幾百萬執行緒，那會用到多少
資源?
    
## Java 21 釋出之後
    ● 有幾個相關的 JEP 還在 Preview 中
○ JEP 446: Scoped Values
○ JEP 453: Structured Concurrency
● 要能完整支援，記得要確認 Web framework、 database driver、HTTP client、message system 等等
○ Spring 6 & SpringBoot 3.2
    
Scoped Values
    
## 提供比 ThreadLocal 輕量且安全的 API ○ 傳遞像 context 的物件
static ScopedValue<Context> CONTEXT = ScopedValue.newInstance();
void serve(Request request, Response response) { var context = createContext(request); ScopedValue.where(CONTEXT, context)
.run(() -> handle(request, response));
}
private void handle(Request request, Response response) { var context = CONTEXT.get();
}
    
## Structured Concurrency
    能把多個在不同執行緒處理的工作當作一個單位 ○ 簡化錯誤處理，取消跟改善不易除錯的問題
    Response handle() throws Exception {
try(var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Supplier<String> user = scope.fork(() -> findUser()); Supplier<Integer> order = scope.fork(() -> fetchOrder()); scope.join().throwIfFailed();
return new Response(user.get(), order.get());
}
}
## 改進 thread-per-request 效率
    
    為了在擴展應用程式的同時能與平台維持協作， 所以用更有效率的方式來實作執行緒
• 如同 OS 將大量虛擬定址空間映射到有限實體 RAM 一樣，JVM 將大量虛擬執行緒映射到少 量的 OS 執行緒，達成增加執行緒數量
• 虛擬執行緒會被臨時對映到載體執行緒中，一 旦遇到阻塞操作，就會從載體中移除，而載體 可以執行另一個虛擬執行緒(新的或之前被阻 塞的)
    
    ## 總結
    
    例如在高 I/O 的後端開發，Virtual Threads 讓 我們可以不用透過 Reactive 的方式來達到高 Throughput
● 不太建議現在馬上導入，記得要檢查看看主要 利用的框架跟函式庫有沒有問題
○ 搭配一些工具來偵測有沒有 Thread pinning 或是預期外的資源被使用
    
## 參考 : 

[淺淡 Virtual Thread - HackMD](https://hackmd.io/@QCZ_Kvv1ScixyAPzRYDKWQ/HJjRAQwCn)

[JCConf 2023 - 深入淺出 Java 21 功能 投影片 | CyberJos is Blogging. 網路老喬的深聊漫談](https://cyberjos.blog/java/seminar/jcconf-2023-head-first-java-21/)

https://docs.google.com/presentation/d/160DkeZv_px5PlolTP5B-ROYs7NVIyrSvTHP96I0yhTY/edit?usp=sharing


