— Привет, Амиго!
Ничего нельзя создать идеальным с первого раза. Это касается и нитей. Со временем разработчики 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 = new 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 или кидает исключение, если оно было. |
— Круто! Так задачи еще и останавливать можно.
— Не сильно на это надейся – не каждую нить можно остановить. Но если задача еще в очереди, то это отлично сработает.
— Такой подход мне нравится. Гораздо удобнее, чем самому создавать нити и потом пробовать вытянуть из них результат.
— Отлично. На этом сегодня и закончим.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ