
ExecutorService: ส่งงาน แล้วปิดพูลให้สะอาด
น้องกายEngineering
ถ้าเคย new Thread(...).start() ทีละงานจนเครื่องสะอึก ปัญหาไม่ได้อยู่ที่จาวาช้าอย่างเดียว แต่อยู่ที่เราไม่ได้จำกัดและปิดทรัพยากรให้ครบ
ExecutorService คือตัวรับงานมาคิวแล้วให้เธรดในพูลรัน แนวทางคลาสสิกคือ Executors.newFixedThreadPool(n) ส่วนบน JDK 21+ มี Executors.newVirtualThreadPerTaskExecutor() ที่แต่ละงานได้ virtual thread ใหม่ เหมาะงาน I/O พร้อมกันสูง ตามเอกสาร Virtual Threads
ตัวอย่างด้านล่างใช้พูลคงที่ที่รันได้บน JDK กว้างกว่า และโชว์การ shutdown + awaitTermination ให้จบสะอาด
เลือกแบบไหน
- Fixed / cached platform pool: งานคำนวณหรือต้องการเพดานเธรดชัด
- Virtual-thread-per-task (JDK 21+): งานบล็อก I/O จำนวนมาก โดยไม่ต้องตั้งขนาดพูลเอง
- อย่าลืมปิดพูล: ไม่งานจะค้างใน JVM ตอนเทสต์หรือตอนปิดแอป
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newFixedThreadPool(2);
try {
Future<String> f = exec.submit(() -> {
Thread.sleep(20);
return "done";
});
String result = f.get(2, TimeUnit.SECONDS);
if (!"done".equals(result)) {
throw new IllegalStateException("unexpected: " + result);
}
System.out.println(result);
} finally {
exec.shutdown();
if (!exec.awaitTermination(2, TimeUnit.SECONDS)) {
exec.shutdownNow();
}
}
}
}
Recap
- ส่งงานผ่าน
ExecutorServiceแทนการสร้างเธรดมือทุกครั้ง - เลือก fixed pool เมื่อต้องการเพดานชัด และพิจารณา virtual-thread-per-task เมื่อขึ้น JDK 21+ กับงาน I/O
- ปิดพูลด้วย
shutdown/shutdownNowทุกครั้งหลังจบ - ใส่ timeout ให้
Future.getเพื่อไม่ค้างเงียบ