ว่าด้วยเรื่อง “Runnable กับ Callable” ใน Java
ใน Multi-thread application (Concurrecy application) ใน Java มี 2 วิธีที่จะสร้าง Thread วิธีที่หนึ่งคือ extends คลาส Thread
และอีกวิธีคือ implementRunnable
แต่อย่างไรก็ตามสิ่งที่ขาดไปของ Runnable คือการ return ผลลัพย์ออกมาเมื่อมันถูก terminate หรือรันจบแล้ว เพื่อที่จะแก้ไขปัญหานี้จึงมี Callable
ดังนั้นในบทความนี้จึงจะมาดูว่าทั้งสอง interface มีความแตกต่างกันอย่างไรบ้าง
Execution Mechanism
ทั้ง 2 Interface ออกแบบให้แทน Task ที่สามารถ execute ด้วยหลายๆ Thread ซึ่งสามารถใช้คลาส Thread แต่ทว่า Callable ไม่สามารถใช้กับคลาส Thread เพื่อสร้าง Thread ได้
Runnable
Runnable interface เป็น functional interface และมี method เดียวคือ run()
ซึ่งไม่รับ parameters และไม่มีการ return ค่าใดๆ
ใช้ในสถานการณ์ที่ไม่ต้องการจะรับ result ใดๆ จากการทำงานของ thread ดังนี้
public interface Runnable {
public void run():
}
ตัวอย่างเช่น
public class RunnableDemo implements Runnable {
private Object result = null;
@Override
public void run() {
Random generator = new Random();
Integer randomNumber = generator.nextInt(5);
try {
Thread.sleep(randomNumber * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
result = randomNumber;
synchronized (this) {
notifyAll();
}
}
public synchronized Object get() throws InterruptedException {
while (result == null) {
wait();
}
return result;
}
}
ซึ่งสามารถรันด้วยการสร้าง Thread และเรียก get()
เพื่อแสดงผลที่ console
public class RunnableDemoTest {
public static void main(String[] args) throws Exception {
RunnableDemo[] randomeTasks = new RunnableDemo[5];
for(int i = 0; i < 5; i++) {
randomeTasks[i] = new RunnableDemo();
Thread t = new Thread(randomeTasks[i]);
t.start();
}
for(int i = 0; i < 5; i++) {
System.out.println(randomeTasks[i].get());
}
}
}
จะได้ผลลัพธ์เป็นค่า random 5 ค่าแสดงบน console
3
2
0
4
2Process finished with exit code 0
Callable
Callable interface เป็น generic interface ที่มี method เดียวคือ call()
ซึ่งจะไม่รับ parameters ใดๆ และจะ return เป็น generic typeV
และมีการ throw exception
public interface Callable<V> {
V call() throws Exception;
}
ตัวอย่างเช่น สร้างคลาส CallableDemo
ที่ implement Callable
interface โดยที่จะ return เป็นค่า random 1– 4 และ throws Exception
public class CallableDemo implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Random generator = new Random();
Integer randomNumber = generator.nextInt(5);
Thread.sleep(randomNumber * 1000);
return randomNumber;
}
}
ซึ่งจะต้องใช้คลาส FuturTask
มาสร้าง Thread เพื่อรัน CallableDemo เนื่องจากว่า Callable ไม่สามารถใช้สร้าง Thread ได้โดยตรง เมือ method call()
ทำงานเสร็จแล้วก็จะเก็บผลลัพธ์ไว้ใน Future
object และเรียก get()
เพื่อแสดงผลที่ console
public class CallableDemoTest {
public static void main(String[] args) throws Exception {
FutureTask[] randomNumberTasks = new FutureTask[5];
for(int i = 0; i < 5; i++) {
Callable callable = new CallableDemo();
randomNumberTasks[i] = new FutureTask(callable);
Thread t = new Thread(randomNumberTasks[i]);
t.start();
}
for(int i = 0; i < 5; i++) {
System.out.println(randomNumberTasks[i].get());
}
}
}
จะได้ผลลัพธ์เป็นค่า random 5 ค่าแสดงบน console
4
4
3
3
0Process finished with exit code 0
จะเห็นได้ว่า Callable จะเหมือนกับ Runnable แต่จะแตกต่างกันที่ Callable จะไม่สามารถสร้าง Thread ได้โดยตรง มีการ return ค่าออกมาตาม generic type และสามารถ throw Exception ออกมาได้ แต่ Runnable สามารถสร้าง Thread ได้โดยตรง แต่จะไม่มีการ return ค่าออกมา และไม่สามารถ throw Exception ได้ สามาเลือกใช้ได้ตามความต้องการ