Concurrent интерфейсы Callable, Future

При работе многопоточного приложения часто необходимо получение от потока результата его деятельности в виде некоторого объекта. Эту задачу можно решить с использованием интерфейсов Callable<V> и Future<V>. Совместное использование двух реализаций данных интерфейсов позволяет получить результат в виде некоторого объекта.

Интерфейс Callable<V>

Интерфейс Callable<V> очень похож на интерфейс Runnable. Объекты, реализующие данные интерфейсы, исполняются другим потоком. Однако, в отличие от Runnable, интерфейс Callable использует Generic'и для определения типа возвращаемого объекта. Runnable содержит метод run(), описывающий действие потока во время выполнения, а Callable – метод call().

С документацией интерфейса Callable<V> можно познакомиться здесь.

Интерфейс Future<V>

Интерфейс Future также, как и интерфейс Callable, использует Generic'и. Методы интерфейса можно использовать для проверки завершения работы потока, ожидания завершения и получения результата. Результат выполнения может быть получен методом get, если поток завершил работу. Прервать выполнения задачи можно методом cancel. Дополнительные методы позволяют определить завершение задачи : нормальное или прерванное. Если задача завершена, то прервать ее уже невозможно.

Методы интерфейса Future

МетодОписание
cancel (boolean mayInterruptIfRunning) попытка завершения задачи
V get() ожидание (при необходимости) завершения задачи, после чего можно будет получить результат
V get(long timeout, TimeUnit unit) ожидание (при необходимости) завершения задачи в течение определенного времени, после чего можно будет получить результат
isCancelled() вернет true, если выполнение задачи будет прервано прежде завершения
isDone() вернет true, если задача завершена

С документацией интерфейса Future<V> можно познакомиться здесь.

Пример использования интерфейсов Callable, Future

Рассмотрим простейший пример использования интерфейсов Callable и Future. Основная идея данного примера – показать, как можно, используя Future, узнать статус Callable потока и получить возвращенный объект. В примере используется объект executor типа ExecutorService, формирующий пул из трех потоков. Метод submit с параметром Callable возвращает объект Future для каждого из стартуемого потоков.

import java.util.Date;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.Future;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ExecutionException;

import java.text.SimpleDateFormat;

public class CallableExample
{
    public CallableExample() 
    {
        // Определяем пул из трех потоков 
        ExecutorService executor = Executors.newFixedThreadPool(3);
         
         // Список ассоциированных с Callable задач Future 
        List<Future<String>>  futures;

        futures = new ArrayList<Future<String>>();

         // Создание экземпляра Callable класса
         Callable<String> callable = new CallableClass();
         
         for (int i = 0; i < 3; i++){
             /*
              * Стартуем возвращаюший результат исполнения 
              * в виде объекта Future поток
              */
             Future<String> future = executor.submit(callable);
             /*
              * Добавляем объект Future в список для отображения 
              * результат выполнения (получение наименования потока)
              */
             futures.add(future);
         }
         SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss  ");
         for (Future<String> future : futures){
             try {
                 // Выводим в консоль полученное значение Future
                 String text = sdf.format(new Date()) + future.get();
                 System.out.println(text);
             } catch (InterruptedException | ExecutionException e) {}
         }
         // Останавливаем пул потоков
         executor.shutdown();
    }
    //---------------------------------------------------------------
    // Класс, реализующий интерфейс Callable
    class CallableClass implements Callable<String>
    {
        @Override
        public String call() throws Exception {
            Thread.sleep(1000);
            // наименование потока, выполняющего callable задачу
            return Thread.currentThread().getName();
        }
    }
    //---------------------------------------------------------------
    public static void main(String args[])
    {
    	new CallableExample();
    }
}

Класс CallableClass, реализующий интерфейс Callable, использует объект String в качестве generic'a. Соответственно и каждый объект Future также должен использовать тип объекта String.

Результат выполнения

Перед остановкой пула потоков в консоль выводятся наименования потока. Т.е. в примере демонстрируется возможность не прямого обращения к методу call класса, реализуещего интерфейс Callable, а косвенно через объект Future, полученного при старте потока.


17:41:16  pool-1-thread-1
17:41:19  pool-1-thread-2
17:41:19  pool-1-thread-3
 
  Рейтинг@Mail.ru