Masalah yang dapat dijalankan

Anda sudah terbiasa dengan antarmuka Runnable dan kelas Thread yang mengimplementasikannya. Mari kita ingat seperti apa antarmuka ini:


public interface Runnable {
	public abstract void run();
}

Perhatikan bahwa tipe kembalian dari metode run adalah void . Tetapi bagaimana jika kita membutuhkan utas kita untuk mengembalikan beberapa hasil pekerjaannya dalam bentuk angka, string, atau objek lain? Maka kita harus menemukan solusinya. Sesuatu seperti ini:


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);
 
	}
 
}

Mari jalankan metode utama berikut :


	public static void main(String[] args) throws Exception {
    		Fibonacci.printByIndex(10);
	}

Konsol akan menampilkan:

Fibonacci angka 10: 34

Kode ini memiliki beberapa kelemahan. Misalnya, sebagai hasil dari pemanggilan metode join , thread utama akan diblokir saat metode printByIndex dijalankan.

Antarmuka yang dapat dipanggil

Sekarang mari kita lihat antarmuka yang langsung disediakan oleh Java, yang dapat digunakan sebagai alternatif untuk Runnable . Ini adalah antarmuka Callable :


public interface Callable<V> {
 
	V call() throws Exception;
 
}

Seperti yang Anda lihat, seperti halnya Runnable , ia hanya memiliki satu metode. Metode ini memiliki tujuan yang sama dengan metode run — metode ini berisi kode yang akan dieksekusi dalam utas paralel. Adapun perbedaannya, lihat nilai pengembaliannya. Sekarang bisa berupa jenis apa pun yang Anda tentukan saat mengimplementasikan antarmuka:


public class CurrentDate implements Callable<Long> {
 
	@Override
 
	public Long call() {
 
    		return new Date().getTime();
 
	}
 
}

Contoh lain:


Callable<String> task = () -> {
 
	Thread.sleep(100);
 
	return "Done";
 
};

Ini hal lain yang berguna — metode panggilan dapat melontarkan Exception . Artinya, tidak seperti metode run , dalam metode panggilan kita tidak harus menangani pengecualian yang diperiksa yang terjadi di dalam metode:


public class Sleep implements Runnable {

	@Override

	public void run() {

    	    try {

        	        Thread.sleep(1000);

    	    } catch (InterruptedException ignored) {

    	    }

	}

}

public class Sleep implements Callable {

	@Override

	public Object call() throws InterruptedException {

    	    Thread.sleep(1000);

    	    return null;

	}

}

Antarmuka masa depan

Antarmuka lain yang bekerja sama dengan Callable adalah Future . Masa depan mewakili hasil perhitungan asinkron (paralel) (nilai yang dikembalikan oleh metode panggilan ). Ini memungkinkan Anda memeriksa apakah perhitungan selesai, menunggu perhitungan selesai, mendapatkan hasil perhitungan, dan banyak lagi.

Metode antarmuka Masa Depan

  • boolean isDone() — metode ini mengembalikan true jika tugas (perhitungan) ini selesai. Tugas yang berakhir secara normal, diakhiri dengan pengecualian, atau dibatalkan dianggap selesai.

  • V get() — jika perlu, metode ini memblokir utas yang memanggilnya, dan mengembalikan hasil perhitungan setelah selesai.

  • V get(long timeout, unit TimeUnit) — seperti metode sebelumnya, metode ini memblokir utas yang memanggilnya, menunggu hasilnya, tetapi hanya untuk waktu yang ditentukan oleh parameter metode.

  • boolean cancel(boolean mayInterruptIfRunning) — metode ini mencoba menghentikan eksekusi tugas. Jika tugas belum mulai berjalan, itu tidak akan pernah berjalan. Jika tugas sedang berlangsung, maka parameter mayInterruptIfRunning menentukan apakah upaya akan dilakukan untuk menghentikan utas yang menjalankan tugas. Setelah metode cancel dipanggil, metode isDone akan selalu mengembalikan true .

  • boolean isCancelled() — metode ini mengembalikan true jika tugas dibatalkan sebelum selesai secara normal. Metode ini akan selalu mengembalikan true jika metode pembatalan sebelumnya dipanggil dan mengembalikan true .

Contoh kode menggunakan Callable dan 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;
 
	}
 
}

Mari jalankan metode utama berikut :


	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);
    		}
	}

Konsol akan menampilkan:

Angka Fibonacci 16: Angka Fibonacci 610 17 : Angka Fibonacci
987 18 : Angka Fibonacci 1597 19: Angka Fibonacci 2584 10: 34 Angka Fibonacci 11: 55 Angka Fibonacci 12: 89 Angka Fibonacci 13: 144 Angka Fibonacci 14: 233 Angka Fibonacci 15: 377