ปัญหาที่รันได้
คุณคุ้นเคยกับ อินเทอร์เฟซ ที่รันได้และคลาสเธรดที่ใช้งานแล้ว จำหน้าตาของอินเทอร์เฟซนี้:
public interface Runnable {
public abstract void run();
}
โปรดทราบว่า ประเภทการ ส่งคืนของเมธอดrun จะเป็น void แต่ถ้าเราต้องการให้เธรดของเราส่งคืนผลงานบางอย่างในรูปแบบของตัวเลข สตริง หรือวัตถุอื่นๆ จากนั้นเราจะต้องคิดวิธีแก้ปัญหา สิ่งนี้:
public class Fibonacci implements Runnable {
private final int index;
private int result;
public Fibonacci(int index) {
this.index = index;
}
@Override
public void run() {
int first = 0;
int second = 1;
if (index == 1) {
result = first;
} else if (index == 2) {
result = second;
} else {
for (int i = 0; i < index - 2; i++) {
int temp = second;
second += first;
first = temp;
}
result = second;
}
}
public static void printByIndex(int index) throws InterruptedException {
Fibonacci fibonacci = new Fibonacci(index);
Thread thread = new Thread(fibonacci);
thread.start();
thread.join();
System.out.println("Fibonacci number " + index + ": " + fibonacci.result);
}
}
ลองใช้ วิธี หลัก ต่อไปนี้ :
public static void main(String[] args) throws Exception {
Fibonacci.printByIndex(10);
}
คอนโซลจะแสดง:
รหัสนี้มีข้อบกพร่องหลายประการ ตัวอย่างเช่น จากการเรียกเมธอดjoinเธรดหลักจะบล็อกในขณะที่ เมธอด printByIndexถูกดำเนินการ
อินเทอร์เฟซที่โทรได้
ทีนี้มาดูอินเทอร์เฟซที่ Java มอบให้เราทันที ซึ่งสามารถใช้เป็นทางเลือกแทนRunnableได้ นี่คือ อินเทอร์เฟซ ที่โทรได้ :
public interface Callable<V> {
V call() throws Exception;
}
อย่างที่คุณเห็น เช่นเดียวกับRunnableมีเพียงวิธีเดียวเท่านั้น วิธีการนี้มีจุดประสงค์เดียวกันกับ วิธี การรัน — มันมีโค้ดที่จะถูกดำเนินการในเธรดคู่ขนาน สำหรับความแตกต่างให้ดูที่ค่าส่งคืน ตอนนี้สามารถเป็นประเภทใดก็ได้ที่คุณระบุเมื่อใช้งานอินเทอร์เฟซ:
public class CurrentDate implements Callable<Long> {
@Override
public Long call() {
return new Date().getTime();
}
}
ตัวอย่างอื่น:
Callable<String> task = () -> {
Thread.sleep(100);
return "Done";
};
มีอย่างอื่นที่เป็นประโยชน์ — วิธี การโทรสามารถโยนข้อยกเว้น ซึ่งหมายความว่า ไม่เหมือนกับ เมธอด runในเมธอดการโทรเราไม่ต้องจัดการข้อยกเว้นที่เลือกซึ่งเกิดขึ้นภายในเมธอด:
|
|
อินเทอร์เฟซในอนาคต
อินเทอร์เฟซอื่นที่ทำงานอย่างใกล้ชิดกับCallableคือFuture Futureแสดงผลของการคำนวณแบบอะซิงโครนัส (แบบขนาน) (ค่าที่ส่งคืนโดยเมธอดการโทร ) ซึ่งช่วยให้คุณตรวจสอบว่าการคำนวณเสร็จสิ้นหรือไม่ รอให้การคำนวณเสร็จสิ้น รับผลการคำนวณ และอื่นๆ
วิธีการของส่วนต่อประสานในอนาคต
-
บูลีน isDone() — วิธีนี้จะคืนค่าจริงหากงานนี้ (การคำนวณ) เสร็จสิ้น งานที่สิ้นสุดตามปกติ สิ้นสุดด้วยข้อยกเว้น หรือถูกยกเลิกถือว่าเสร็จสิ้น
-
V get() — หากจำเป็น เมธอดนี้จะบล็อกเธรดที่เรียกใช้ และส่งคืนผลลัพธ์ของการคำนวณเมื่อเสร็จสิ้น
-
V get(long timeout, TimeUnit unit) — เช่นเดียวกับวิธีก่อนหน้า เมธอดนี้จะบล็อกเธรดที่เรียกมัน รอผลลัพธ์ แต่เฉพาะเวลาที่ระบุโดยพารามิเตอร์เมธอดเท่านั้น
-
การยกเลิกบูลีน (บูลีน mayInterruptIfRunning) - วิธีนี้พยายามหยุดการทำงานของงาน ถ้างานยังไม่เริ่มทำงาน ก็จะไม่ทำงาน หากงานอยู่ระหว่างดำเนินการ พารามิเตอร์ mayInterruptIfRunningจะพิจารณาว่าจะมีการพยายามขัดจังหวะเธรดที่เรียกใช้งานหรือไม่ หลังจากเรียกเมธอดcancel เมธอด isDoneจะคืนค่า trueเสมอ
-
บูลีน isCancelled() — วิธีนี้จะคืนค่าจริงหากงานถูกยกเลิกก่อนที่จะเสร็จสิ้นตามปกติ เมธอดจะคืนค่าจริง เสมอ หาก เมธอด ยกเลิกถูกเรียกก่อนหน้านี้และส่งคืนค่าจริง
ตัวอย่างโค้ดที่ใช้ Callable และ Future
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
public class Fibonacci implements Callable<Integer> {
private final int index;
public Fibonacci(int index) {
this.index = index;
}
@Override
public Integer call() {
int first = 0;
int second = 1;
if (index == 1) {
return first;
} else if (index == 2) {
return second;
} else {
for (int i = 0; i < index - 2; i++) {
int temp = second;
second += first;
first = temp;
}
return second;
}
}
public static Future<Integer> calculateAsync(int index) throws Exception {
Fibonacci fibonacci = new Fibonacci(index);
// The future object will represent the result of running the fibonacci task.
FutureTask<Integer> future = new FutureTask<>(fibonacci);
// Because the FutureTask class implements both the Future interface and the Runnable interface,
// you can pass instances of it to the Thread constructor
Thread thread = new Thread(future);
thread.start();
return future;
}
}
ลองใช้ วิธี หลัก ต่อไปนี้ :
public static void main(String[] args) throws Exception {
Map<Integer, Future<Integer>> tasks = new HashMap<>();
for (int i = 10; i < 20; i++) {
tasks.put(i, Fibonacci.calculateAsync(i));
}
for (Map.Entry<Integer, Future<Integer>> entry : tasks.entrySet()) {
Future<Integer> task = entry.getValue();
int index = entry.getKey();
int result;
// Check whether the task is done
if (task.isDone()) {
// Get the result of the calculations
result = task.get();
} else {
try {
// Wait another 100 milliseconds for the result of the calculations
result = task.get(100, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
// Interrupt the task
task.cancel(true);
System.out.println("Fibonacci number " + index + " could not be calculated in the allotted time.");
return;
}
}
System.out.println("Fibonacci number " + index + ": " + result);
}
}
คอนโซลจะแสดง:
หมายเลขฟีโบนักชี 17: 987
หมายเลขฟีโบนักชี 18: 1597 หมายเลข
ฟีโบนักชี 19: 2584 หมายเลข
ฟีโบนักชี 10: 34 หมายเลข ฟีโบนักชี 11: 55 หมายเลขฟีโบ นักชี 12: 89 หมายเลข
ฟีโบนักชี 13: 144 หมายเลขฟี โบนักชี 14: 233 หมายเลขฟีโบนักชี 15:377