Future และการจัดการข้อผิดพลาด
ใช้ Future.get พร้อมการหมดเวลา จัดการ ExecutionException และยกเลิกงานที่กำลังทำงาน
Future และการจัดการข้อผิดพลาด เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
Future คืออะไร
Future<V> แทนผลลัพธ์ที่ยังรออยู่ของการคำนวณแบบไม่พร้อมกัน โดยมีเมธอดสำหรับตรวจสอบการเสร็จสิ้น รอผลลัพธ์ และจัดการข้อผิดพลาด
import java.util.concurrent.*;
ExecutorService pool = Executors.newFixedThreadPool(2);
Future<Integer> future = pool.submit(() -> {
Thread.sleep(1000);
return 42;
});
System.out.println("Is done? " + future.isDone()); // false
Integer result = future.get(); // blocks
System.out.println("Result: " + result); // 42
pool.shutdown();future.get() พร้อมการหมดเวลา
ควรใช้รูปแบบที่มีการหมดเวลาเสมอ เพื่อป้องกันการค้างรออย่างไม่มีกำหนด
try {
Integer result = future.get(5, TimeUnit.SECONDS);
System.out.println(result);
} catch (TimeoutException e) {
System.out.println("Timed out");
future.cancel(true); // interrupt the task
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} catch (ExecutionException e) {
System.out.println("Task threw: " + e.getCause());
}ExecutionException
หากงานส่งข้อยกเว้น future.get() จะห่อหุ้มข้อยกเว้นนั้นไว้ใน ExecutionException ให้แกะข้อยกเว้นด้วย getCause()
Future<String> failing = pool.submit(() -> {
throw new IllegalArgumentException("bad input");
});
try {
failing.get();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
System.out.println(cause.getClass().getSimpleName()); // IllegalArgumentException
System.out.println(cause.getMessage()); // bad input
}การยกเลิก Future
cancel(mayInterruptIfRunning) จะพยายามยกเลิกงาน และส่งคืนค่า true หากยกเลิกสำเร็จ หาก mayInterruptIfRunning เป็น true ระบบจะส่งสัญญาณหยุดไปยังเธรดที่กำลังทำงาน
Future<String> f = pool.submit(() -> {
try {
Thread.sleep(10_000); // long task
return "done";
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return "interrupted";
}
});
boolean cancelled = f.cancel(true); // send interrupt
System.out.println("Cancelled: " + cancelled); // true
System.out.println("Is cancelled: " + f.isCancelled()); // trueisCancelled เทียบกับ isDone
isDone() ส่งคืนค่า true หากงานเสร็จตามปกติ ส่งข้อยกเว้น หรือถูกยกเลิก ส่วน isCancelled() จะส่งคืนค่า true เฉพาะเมื่องานถูกยกเลิกเท่านั้น
// After cancel:
System.out.println(f.isDone()); // true
System.out.println(f.isCancelled()); // true
// After normal completion:
Future<Integer> done = pool.submit(() -> 5);
done.get(); // wait
System.out.println(done.isDone()); // true
System.out.println(done.isCancelled()); // falseCompletionService สำหรับผลลัพธ์ที่พร้อมก่อน
ExecutorCompletionService จะห่อหุ้มกลุ่มเธรดและมีเมธอด take() สำหรับดึง Future ที่เสร็จถัดไปตามลำดับการเสร็จ ไม่ใช่ลำดับการส่งงาน
ExecutorCompletionService<Integer> cs =
new ExecutorCompletionService<>(pool);
for (int i = 0; i < 5; i++) {
final int delay = 5 - i; // submit fastest last
cs.submit(() -> { Thread.sleep(delay * 100); return delay; });
}
for (int i = 0; i < 5; i++) {
Future<Integer> f = cs.take(); // next completed
System.out.println(f.get());
}การจัดการ Future หลายรายการอย่างปลอดภัย
เมื่อรวบรวมผลลัพธ์จาก Future หลายรายการ ให้ทำซ้ำตรวจสอบและจัดการข้อยกเว้นแยกสำหรับแต่ละ Future
List<Future<String>> futures = new ArrayList<>();
for (int i = 0; i < 5; i++) {
final int id = i;
futures.add(pool.submit(() ->
id % 2 == 0 ? "ok_" + id : (() -> { throw new RuntimeException("fail_"+id); }).get()
));
}
for (Future<String> f : futures) {
try {
System.out.println(f.get());
} catch (ExecutionException e) {
System.out.println("Error: " + e.getCause().getMessage());
}
}Future.get() หลังปิดกลุ่มเธรด
การส่งงานหลังจาก shutdown() จะส่ง RejectedExecutionException แต่ Future ที่ส่งไว้ก่อนการปิดกลุ่มเธรดยังสามารถดึงผลลัพธ์ได้หลังจากปิดแล้ว
ExecutorService pool2 = Executors.newFixedThreadPool(2);
Future<Integer> f = pool2.submit(() -> 99);
pool2.shutdown(); // no new tasks
// Still valid — task was submitted before shutdown:
System.out.println(f.get()); // 99
try {
pool2.submit(() -> 0); // throws!
} catch (RejectedExecutionException e) {
System.out.println("Pool shut down");
}FutureTask: Future แบบจัดการด้วยตนเอง
FutureTask<V> ใช้งานได้ทั้งในฐานะ Runnable และ Future<V> จึงมีประโยชน์เมื่อต้องการ Future โดยไม่ใช้ ExecutorService
FutureTask<String> task = new FutureTask<>(() -> "computed");
new Thread(task).start(); // run in any thread
System.out.println(task.get()); // computedรูปแบบการลองใหม่ด้วย Future
นำตรรกะการลองใหม่อย่างง่ายมาใช้ครอบ future.get()
Future<String> future = pool.submit(() -> {
if (Math.random() < 0.7) throw new RuntimeException("transient error");
return "success";
});
for (int attempt = 0; attempt < 3; attempt++) {
try {
System.out.println(future.get());
break;
} catch (ExecutionException e) {
System.out.println("Attempt " + (attempt+1) + " failed");
if (attempt == 2) throw e;
future = pool.submit(() -> "retry"); // resubmit
}
}ข้อจำกัดของ Future
java.util.concurrent.Future มีข้อจำกัดดังนี้
- ไม่มีการเรียกกลับ ต้องหยุดรอด้วย get()
- ไม่สามารถเชื่อมต่อการแปลงผลลัพธ์เป็นลำดับได้
- ไม่สามารถรวม Future หลายรายการเข้าด้วยกันได้
ให้ใช้ CompletableFuture (ในหลักสูตรถัดไป) สำหรับการรวมการทำงานแบบตอบสนองและไม่หยุดรอ
ตรวจสอบความเข้าใจอย่างรวดเร็ว
งานหนึ่งส่งข้อยกเว้น เมื่อคุณเรียก future.get() จะเกิดข้อยกเว้นใด
สรุป: Future และการจัดการข้อผิดพลาด
ประเด็นสำคัญที่ควรจำ
- future.get() จะหยุดรอ ควรใช้รูปแบบที่มีการหมดเวลาเสมอ
- ExecutionException ห่อหุ้มข้อยกเว้นจากงาน ให้แกะด้วย getCause()
- cancel(true) ส่งสัญญาณหยุด ส่วน isDone/isCancelled ใช้ตรวจสอบสถานะ
- ExecutorCompletionService.take() ดึง Future ตามลำดับการเสร็จ
- FutureTask ใช้งานได้ทั้งในฐานะ Runnable และ Future
คำถามที่พบบ่อย
บทเรียน “Future และการจัดการข้อผิดพลาด” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “Future และการจัดการข้อผิดพลาด” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “Future และการจัดการข้อผิดพลาด”
ใช้ Future.get พร้อมการหมดเวลา จัดการ ExecutionException และยกเลิกงานที่กำลังทำงาน คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 3 จากทั้งหมด 4 บทเรียน
บทเรียน “Future และการจัดการข้อผิดพลาด” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ExecutorService และชนิดพูลเธรด
- การส่งงาน: Runnable กับ Callable
- Future และการจัดการข้อผิดพลาด
- ScheduledExecutorService สำหรับงานที่ทำซ้ำ