— Привіт, Аміго!
Нічого не можна створити ідеальним з першого разу. Це стосується і ниток. Згодом розробники Java переконалися, що інтерфейс Runnable не ідеальний. Він не підтримував перекидання винятків і не дозволяв дізнатися про результат виконання завдання.
Інтерфейс Runnable скоріше підходить для великих незалежних завдань, ніж для маленьких підзадач, яких хочеться запустити з десяток одночасно, а потім зібрати з них результати їхньої роботи.
Тому було придумано інтерфейс Callable. Він набагато краще підходить для паралельного виконання невеликих завдань, ніж Runnable і Thread, ще й тому, що є generic-інтерфейсом.
Ось типовий клас, який реалізує інтерфейс:
class ReverseString implements Callable<String> ;
{
String str;
ReverseString(String str)
{
this.str = str;
}
public String call() throws Exception
{
StringBuilder builder = новий StringBuilder(str);
builder.reverse();
return builder.toString();
}
}
На відміну від Runnable, тут ми повинні перевизначити метод call, який повертає результат, заданий типом-параметром. Такий підхід набагато зручніший, ніж метод run інтерфейсу Runnable, який повертає void. Іноді розробникам доводилося вигадувати різні «обхідні шляхи», щоб отримати результат нитки.
— Ясно.
— А тепер дивись, як Callable може працювати в парі з ThreadPoolExecutor:
По-перше, метод submit класу ThreadPoolExecutor повертає параметризований об'єкт типу Future. Цей об'єкт можна використовувати, щоб дізнатися, чи завершилося виконання завдання, а також, щоб отримати результат його виконання.
Ось як це працює:
//1. Створюємо ThreadPoolExecutor
ExecutorService service = Executors.newFixedThreadPool(5);
//2 поміщаємо у нього завдання до виконання
Future<String> task = service.submit(new ReverseString("Amigo" ));
//3 чекаємо поки завдання виконається
while(!task.isDone())
{
Thread.sleep(1);
}
//4 пробуємо отримати результат завдання
//отримаємо або результат чи виняток, якщо він був під час виконання завдання
try
{
System.out.println("Розгорнутий рядок : " + task.get());
}
catch (Exception ie)
{
ie.printStackTrace(System.err);
}
//5 зупиняємо ThreadPool.
service.shutdown();
— Круто! Особливо інтерфейс Future сподобався. А які у нього методи?
— Ось найцікавіші:
Метод | Опис |
---|---|
|
Зупиняє завдання. |
|
Повертає true, якщо завдання було зупинено. |
|
Повертає true, якщо виконання завдання завершено. |
|
Повертає результат виклику методу call або кидає виняток, якщо він був. |
— Круто! Так завдання ще й зупиняти можна.
— Не сильно на це сподівайся – не кожну нитку можна зупинити. Але якщо завдання ще в черзі, то це добре спрацює.
— Такий підхід мені подобається. Набагато зручніше, ніж самому створювати нитки і пробувати витягнути з них результат.
— Чудово. На цьому сьогодні й закінчимо.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ