Runnable muammosi
Siz allaqachon Runnable interfeysi va uni amalga oshiruvchi Thread klassi bilan tanishsiz. Keling, shu interfeys qanday ko'rinishda ekanligini eslab o'taylik:
public interface Runnable {
public abstract void run();
}
E'tibor bering, run metodining qaytish qiymati — void. Lekin, agar bizga ipning ish faoliyatidan biror natija olish kerak bo'lsa, masalan, raqam, matn yoki boshqa biror obyekt ko'rinishida, unda qandaydir yo'l bilan ularni qo'lga kiritishimiz kerak bo'ladi, masalan, bunday:
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(index + "-soni Fibonaccining: " + fibonacci.result);
}
}
Bu kabi metodni maindan ishga tushiramiz:
public static void main(String[] args) throws Exception {
Fibonacci.printByIndex(10);
}
Konsolda quyidagilar chiqadi:
Bu kodda bir qator kamchiliklar mavjud. Masalan, bosh ip printByIndex metodining chaqirilishi vaqtida bloklanadi, chunki u metod join metodini o'z ichiga oladi.
Callable interfeysi
Endi keling, Java bizga "qutidan tashqarida" taklif qilayotgan va Runnablega alternativ bo'la oladigan interfeysni ko'rib chiqamiz. Bu Callable interfeysi:
public interface Callable<V> {
V call() throws Exception;
}
Ko'rib turganingizdek, bu interfeysda ham Runnable kabi faqat bitta metod mavjud. Metodning vazifasi run metodi kabi, ya'ni u parallel ipda bajariladigan kodni o'z ichida jamlaydi. Farqi shundaki, natijani qaytarish mumkin. Endi interfeysni amalga oshirayotganda siz qanday turdagi qiymatni qaytarishini ko'rsatishingiz mumkin:
public class CurrentDate implements Callable<Long> {
@Override
public Long call() {
return new Date().getTime();
}
}
Yana bir misol:
Callable<String> task = () -> {
Thread.sleep(100);
return "Tayyor";
};
Yana bir foydali jihati: call metodi Exceptionni tashlash imkoniyatiga ega bo'lishi, demak run metodi kabi bu yerda tekshiriladigan istisnolarga e'tibor bermaslik mumkin:
|
|
Future interfeysi
Yana bir interfeys bor, u Callable bilan yaqin aloqada ishlaydi, bu Future. Future asinxron (parallel) hisoblashlarning natijasini ifodalaydi (ya'ni, call metodi qaytaradigan qiymat). Bu interfeys hisoblashlar tugagan-tugamagani, hisoblashlar natijasini olish va boshqa holatlarni tekshirish imkoniyatini beradi.
Future metodlari
boolean isDone() — bu metod trueni qaytaradi, agar bu vazifa (hisoblashlar) tugagan bo'lsa. Vazifalar tugagan deb hisoblanadi, agar ular odatiy tarzda tugagan, istisno bilan tugagan yoki bekor qilingan bo'lsa.
V get() — bu metod agar kerak bo'lsa, uni chaqirgan ipni bloklaydi va hisoblashlar tugagandan so'ng ularning natijasini chiqaradi.
V get(long timeout, TimeUnit unit) — oldingi metod kabi, lekin bu safar natija kutishda metod parametrlarida berilgan vaqtni belgilaydi.
boolean cancel(boolean mayInterruptIfRunning) — bu metod vazifaning bajarilishini to'xtatishga harakat qiladi. Agar vazifa hali boshlanmagan bo'lsa, u endi hech qachon ishga tushmaydi. Agar vazifa bajarilayotgan bo'lsa, mayInterruptIfRunning parametri, vazifani bajaruvchi ipni to'xtatishga urinish kerakmi yoki yo'qligini belgilaydi. cancel metodi chaqirilgandan keyin, isDone metodi har doim trueni qaytaradi.
boolean isCancelled() — bu metod trueni qaytaradi, agar vazifa odatiy tarzda tugamasdan bekor qilingan bo'lsa. Bu metod har doim trueni qaytaradi, agar undan oldin cancel metodi chaqirilgan bo'lsa va u trueni qaytargan bo'lsa.
Callable va Future kod misoli
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);
// future obyekti fibonacci vazifasi hisoblashlarining natijasini ifodalaydi
FutureTask<Integer> future = new FutureTask<>(fibonacci);
// FutureTask klassi ham Future interfeysini ham Runnable interfeysni amalga oshiradi, shuning uchun
// uni Thread konstruktoriga uzatish mumkin
Thread thread = new Thread(future);
thread.start();
return future;
}
}
Bu kabi metodni maindan ishga tushiramiz:
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;
// Vazamiz tugagan-tugamagani tekshiramiz
if (task.isDone()) {
// Hisoblashlar natijasini olamiz
result = task.get();
} else {
try {
// Hisoblashlar natijasini yana 100 millisekund kutamiz
result = task.get(100, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
// Vazifani bajarilishini to'xtatamiz
task.cancel(true);
System.out.println("Fibonaccining " + index + "-sonini hisoblash belgilangan vaqtga sig'madi.");
return;
}
}
System.out.println(index + "-soni Fibonaccining: " + result);
}
}
Konsolda quyidagilar chiqadi:
Fibonaccining 17-soni: 987
Fibonaccining 18-soni: 1597
Fibonaccining 19-soni: 2584
Fibonaccining 10-soni: 34
Fibonaccining 11-soni: 55
Fibonaccining 12-soni: 89
Fibonaccining 13-soni: 144
Fibonaccining 14-soni: 233
Fibonaccining 15-soni: 377
GO TO FULL VERSION