ความแตกต่างระหว่าง Runnable และ Callable ใน Java
ทั้งสองเป็น Functional Interface สำหรับ Multithreading แตกต่างกันที่ ค่าส่งคืน, ข้อยกเว้น, และ วิธีการรัน
ตารางเปรียบเทียบ
| คุณสมบัติ | Runnable | Callable<V> |
|---|---|---|
| Package | java.lang | java.util.concurrent |
| เมธอดหลัก | void run() |
V call() throws Exception |
| ค่าส่งคืน | ไม่มี (void) | มี (Generic Type V) |
| Checked Exception | ไม่สามารถโยนได้ | โยนได้ (throws Exception) |
| การรัน Thread | new Thread(runnable).start() |
ต้องใช้ ExecutorService |
| ผลลัพธ์ Async | ไม่ได้โดยตรง | Future<V> จาก submit() |
| Bulk Execution | ไม่รองรับ | invokeAll(), invokeAny() |
| Functional Interface | ✅ (Single Abstract Method) | ✅ (Single Abstract Method) |
ตัวอย่าง Runnable
public class RunnableExample implements Runnable {
@Override
public void run() {
System.out.println("Hello from Runnable! Thread: " + Thread.currentThread().getName());
}
public static void main(String[] args) {
// วิธี 1: Thread constructor
new Thread(new RunnableExample()).start();
// วิธี 2: Lambda (Java 8+)
new Thread(() -> System.out.println("Lambda Runnable")).start();
// วิธี 3: Anonymous class
new Thread(new Runnable() {
@Override public void run() {
System.out.println("Anonymous Runnable");
}
}).start();
}
}
ตัวอย่าง Callable
import java.util.concurrent.*;
public class CallableExample implements Callable {
@Override
public String call() throws Exception {
System.out.println("In call() - Thread: " + Thread.currentThread().getName());
Thread.sleep(1000); // จำลองงานหนัก
return "Result from Callable";
}
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newSingleThreadExecutor();
// Submit คืนค่า Future
Future future = executor.submit(new CallableExample());
System.out.println("Main thread doing other work...");
// get() บล็อกจนกว่าจะได้ผลลัพธ์
String result = future.get();
System.out.println("Result: " + result);
executor.shutdown();
}
}
ผลลัพธ์ Callable
Main thread doing other work...
In call() - Thread: pool-1-thread-1
Result: Result from Callable
การใช้งาน Callable แบบทันสมัย (Java 8+ Lambda)
ExecutorService executor = Executors.newFixedThreadPool(3);
List> tasks = List.of(
() -> { Thread.sleep(100); return 1; },
() -> { Thread.sleep(200); return 2; },
() -> { Thread.sleep(300); return 3; }
);
// รันทั้งหมดรอจบ (invokeAll)
List> futures = executor.invokeAll(tasks);
for (Future f : futures) {
System.out.println("Result: " + f.get());
}
// รันใครเร็วสุดเอา (invokeAny)
Integer fastest = executor.invokeAny(tasks);
System.out.println("Fastest result: " + fastest);
executor.shutdown();
CompletableFuture (Java 8+) - ทันสมัยกว่า
// Non-blocking, composable
CompletableFuture future = CompletableFuture.supplyAsync(() -> {
// Heavy computation
return "Async Result";
});
future.thenAccept(result -> System.out.println("Got: " + result));
// หรือ
String result = future.join(); // Blocking
แนวทางเลือกใช้
- Runnable: งานที่ไม่ต้องส่งค่ากลับ (Fire-and-forget, Logging, Background tasks)
- Callable: งานที่ต้องการผลลัพธ์ คำนวณซับซ้อน อาจโยน Exception
- CompletableFuture: Async programming ทันสมัย Chaining, Combining, Exception handling ดีกว่า
- Virtual Threads (Java 21+): ใช้ Runnable ธรรมดา แต่ Scalability สูงมาก