Ang Runnable na problema

Pamilyar ka na sa Runnable interface at sa Thread class na nagpapatupad nito. Alalahanin natin kung ano ang hitsura ng interface na ito:


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

Tandaan na ang uri ng pagbabalik ng run method ay walang bisa . Ngunit paano kung kailangan namin ang aming thread upang ibalik ang ilang resulta ng trabaho nito sa anyo ng isang numero, isang string, o ilang iba pang bagay? Pagkatapos ay dapat tayong makabuo ng isang solusyon. Isang bagay na tulad nito:


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

Patakbuhin natin ang sumusunod na pangunahing pamamaraan:


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

Ipapakita ng console ang:

Fibonacci number 10: 34

Ang code na ito ay may ilang mga kakulangan. Halimbawa, bilang resulta ng tawag sa paraan ng pagsali , ang pangunahing thread ay haharang habang ang printByIndex na paraan ay isinasagawa.

Matatawag na interface

Ngayon tingnan natin ang interface na ibinibigay sa atin ng Java sa labas ng kahon, na maaaring magamit bilang alternatibo sa Runnable . Ito ang Callable interface:


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

Tulad ng nakikita mo, tulad ng Runnable , mayroon lamang itong isang paraan. Ang pamamaraang ito ay nagsisilbi sa parehong layunin tulad ng run method — naglalaman ito ng code na isasagawa sa isang parallel thread. Tulad ng para sa mga pagkakaiba, tingnan ang return value. Ngayon ay maaari itong maging anumang uri na iyong tinukoy kapag ipinapatupad ang interface:


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

Isa pang halimbawa:


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

Narito ang ibang bagay na kapaki-pakinabang — ang paraan ng pagtawag ay maaaring maghagis ng Exception . Nangangahulugan iyon na, hindi tulad ng run method, sa call method hindi namin kailangang pangasiwaan ang mga nasuri na exception na nangyayari sa loob ng method:


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;

	}

}

Hinaharap na interface

Ang isa pang interface na malapit na gumagana sa Callable ay Future . Kinakatawan ng hinaharap ang resulta ng asynchronous (parallel) computations (ang halaga na ibinalik ng paraan ng pagtawag ). Hinahayaan ka nitong suriin kung tapos na ang mga kalkulasyon, hintaying matapos ang mga kalkulasyon, makuha ang resulta ng mga kalkulasyon, at higit pa.

Paraan ng hinaharap na interface

  • boolean isDone() — ang paraang ito ay nagbabalik ng totoo kung ang gawaing ito (pagkukuwenta) ay tapos na. Ang mga gawaing natapos nang normal, natapos nang may exception, o kinansela ay itinuturing na tapos na.

  • V get() — kung kinakailangan, hinaharangan ng pamamaraang ito ang thread na tumawag dito, at ibinabalik ang resulta ng mga kalkulasyon kapag tapos na ang mga ito.

  • V get(mahabang timeout, TimeUnit unit) — tulad ng nakaraang pamamaraan, hinaharangan ng pamamaraang ito ang thread na tumawag dito, naghihintay ng resulta, ngunit para lamang sa oras na tinukoy ng mga parameter ng pamamaraan.

  • boolean cancel(boolean mayInterruptIfRunning) — ang pamamaraang ito ay sumusubok na pigilan ang pagsasagawa ng gawain. Kung ang gawain ay hindi pa nagsisimulang tumakbo, hindi ito tatakbo. Kung ang gawain ay isinasagawa, ang mayInterruptIfRunning na parameter ay tumutukoy kung ang isang pagtatangka ay gagawin upang matakpan ang thread na nagpapatupad ng gawain. Pagkatapos tawagin ang paraan ng pagkansela , ang isDone na paraan ay palaging magbabalik ng true .

  • boolean isCancelled() — ang pamamaraang ito ay nagbabalik ng true kung ang gawain ay kinansela bago ito matapos nang normal. Ang pamamaraan ay palaging magbabalik ng true kung ang paraan ng pagkansela ay dating tinawag at ibinalik na totoo .

Halimbawa ng code gamit ang Callable at 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;
 
	}
 
}

Patakbuhin natin ang sumusunod na pangunahing pamamaraan:


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

Ipapakita ng console ang:

Fibonacci number 16: 610
Fibonacci number 17: 987
Fibonacci number 18: 1597
Fibonacci number 19: 2584
Fibonacci number 10: 34
Fibonacci number 11: 55 Fibonacci
number 12
: 89 Fibonacci number 413
Fibonacci number 413
Fibonacci number 413 15: 377