0Pricing
Java Academy · บทเรียน

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()); // true

isCancelled เทียบกับ 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()); // false

CompletionService สำหรับผลลัพธ์ที่พร้อมก่อน

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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ExecutorService และชนิดพูลเธรด
  2. การส่งงาน: Runnable กับ Callable
  3. Future และการจัดการข้อผิดพลาด
  4. ScheduledExecutorService สำหรับงานที่ทำซ้ำ
← กลับไปที่ Java Academy