
Virtual thread pinning เบื้องต้น: อะไรเคยพิน และอะไรยังพินอยู่
Virtual thread ทำให้เราเปิดงานรอ I/O จำนวนมากได้โดยไม่ต้องจอง platform thread ทีละเส้น แต่ถ้า virtual thread ถูก pin กับ carrier นาน ๆ ความสามารถสเกลจะลดลงครับ
Pinning คืออะไรแบบสั้น ๆ
ปกติ virtual thread ที่บล็อกแบบที่ JVM รู้จักจะ unmount จาก carrier เพื่อให้ carrier ไปรับงานอื่น ถ้ายังถือสถานะที่ทำให้ unmount ไม่ได้ มันจะ pin อยู่กับ carrier
บน JDK 21–23 การเข้า synchronized แล้วบล็อกยาว หรือ Object.wait() เป็นสาเหตุพินที่พูดถึงบ่อย ตามเอกสาร virtual threads ยุคนั้น
ตั้งแต่ JEP 491 ใน JDK 24 การ synchronize แบบเดิมไม่ทำให้พินแบบเดิมแล้ว เหลือเคสที่ยังต้องระวัง เช่น กรอบ native / JNI / FFM ที่ยังอยู่บน carrier
ถ้ายังอยู่ JDK 21 LTS ให้ถือว่าคำเตือนเรื่อง synchronized + blocking ยังใช้ได้ หรือวางแผนอัปไปสายที่มี JEP 491
HOW: ตัวอย่าง Main แยกงานบน virtual thread
ตัวอย่างด้านล่างเป็น fragment สำหรับอ่านแนวคิด
import java.util.concurrent.atomic.AtomicReference;
public class Main {
public static void main(String[] args) throws Exception {
AtomicReference<String> result = new AtomicReference<>();
Thread vthread = Thread.ofVirtual().start(() -> {
try {
Thread.sleep(20);
result.set("done-on-virtual");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
result.set("interrupted");
}
});
vthread.join();
assert "done-on-virtual".equals(result.get());
assert vthread.isVirtual();
}
}
สิ่งที่ผมเช็กในโปรเจกต์จริง
- งาน I/O หนักอยู่ใน virtual thread pool ของตัวเองหรือไม่
- บน JDK 21 มี
synchronizedรอบ blocking นานหรือไม่ - เปิด JFR มอง
jdk.VirtualThreadPinnedตอนโหลดเทส
Recap
- Pinning = virtual thread ถอดจาก carrier ไม่ได้ชั่วคราว
- JDK 21–23:
synchronized+ block ยาวเป็นจุดเสี่ยงหลัก - JDK 24+: JEP 491 ลดพินจาก monitor; ยังระวัง native frames
- ใช้ JFR ไม่ใช่แค่เดาจากโค้ดครับ