Рубрики

Callable и будущее в Java

Необходимое условие: Темы , Многопоточность

Потребность в Callable

Существует два способа создания потоков — один путем расширения класса Thread, а другой — создания потока с Runnable. Однако в Runnable отсутствует одна особенность, заключающаяся в том, что мы не можем сделать поток, возвращающий результат, когда он завершается, т.е. когда run () завершается. Для поддержки этой функции в Java присутствует интерфейс Callable.

Callable против Runnable

  • Для реализации Runnable должен быть реализован метод run (), который ничего не возвращает, в то время как для Callable должен быть реализован метод call (), который возвращает результат по завершении. Обратите внимание, что поток не может быть создан с помощью Callable, он может быть создан только с Runnable.
  • Другое отличие состоит в том, что метод call () может вызвать исключение, тогда как метод run () не может.

Подпись метода, которая должна быть переопределена для реализации Callable.

public Object call() throws Exception;

Вот код для примера Callable, который вернет случайное число после задержки около 0 — 4 секунд.

// Java-программа для иллюстрации Callable
// вернуть случайное число

import java.util.Random;

import java.util.concurrent.Callable;

import java.util.concurrent.FutureTask;

  

class CallableExample implements Callable

{

  

    public Object call() throws Exception

    {

        // Создать генератор случайных чисел

        Random generator = new Random();

  

        Integer randomNumber = generator.nextInt(5);

  

        // Для имитации тяжелых вычислений,

        // мы задерживаем поток на некоторое случайное время

        Thread.sleep(randomNumber * 1000);

  

        return randomNumber;

    }

}

Будущее

Когда метод call () завершается, ответ должен быть сохранен в объекте, известном основному потоку, чтобы основной поток мог знать о результате, возвращенном потоком. Как программа сохранит и получит этот результат позже? Для этого можно использовать объект Future. Думайте о Будущем как о объекте, который содержит результат — он может не удерживать его прямо сейчас, но он будет делать это в будущем (как только Callable вернется). Таким образом, будущее — это в основном один из способов, которым основной поток может отслеживать прогресс и результат других потоков. Для реализации этого интерфейса необходимо переопределить 5 методов, но, как показано в примере ниже, используется конкретная реализация из библиотеки, здесь перечислены только важные методы.

Заметьте, что Callable и Future делают две разные вещи — Callable похож на Runnable в том, что он инкапсулирует задачу, предназначенную для выполнения в другом потоке, тогда как Future используется для хранения результата, полученного из другого потока. Фактически, Future может быть настроен на работу и с Runnable, и это станет ясно, когда исполнители появятся.

  • public boolean cancel (логическое mayInterrupt): используется для остановки задачи. Он останавливает задачу, если она еще не началась. Если он запущен, он прерывает задачу, только если mayInterrupt имеет значение true.
  • public Object get () создает InterruptedException, ExecutionException: используется для получения результата задачи. Если задача завершена, она немедленно возвращает результат, в противном случае она ждет, пока задача будет завершена, и затем возвращает результат.
  • public boolean isDone (): возвращает true, если задача выполнена, и false в противном случае

Для создания потока требуется Runnable. Для получения результата требуется будущее.

Библиотека Java имеет конкретный тип FutureTask, который реализует Runnable и Future, сочетая удобство обеих функций.
FutureTask можно создать, предоставив его конструктору Callable. Затем объект FutureTask предоставляется конструктору Thread для создания объекта Thread. Таким образом, косвенно поток создается с помощью Callable. Для дальнейшего акцентирования, обратите внимание, что нет способа создать поток напрямую с помощью Callable.

Вот код для полного примера с использованием Callable и FutureTask.

// Java-программа для иллюстрации Callable и FutureTask
// для генерации случайных чисел

import java.util.Random;

import java.util.concurrent.Callable;

import java.util.concurrent.FutureTask;

  

class CallableExample implements Callable

{

  

  public Object call() throws Exception

  {

    Random generator = new Random();

    Integer randomNumber = generator.nextInt(5);

  

    Thread.sleep(randomNumber * 1000);

  

    return randomNumber;

  }

  
}

  

public class CallableFutureTest

{

  public static void main(String[] args) throws Exception

  {

  

    // FutureTask - это конкретный класс, который

    // реализует как Runnable, так и Future

    FutureTask[] randomNumberTasks = new FutureTask[5];

  

    for (int i = 0; i < 5; i++)

    {

      Callable callable = new CallableExample();

  

      // Создаем FutureTask с Callable

      randomNumberTasks[i] = new FutureTask(callable);

  

      // Поскольку он реализует Runnable, создайте поток

      // с FutureTask

      Thread t = new Thread(randomNumberTasks[i]);

      t.start();

    }

  

    for (int i = 0; i < 5; i++)

    {

      // Поскольку он реализует Future, мы можем вызвать get ()

      System.out.println(randomNumberTasks[i].get());

  

      // Этот метод блокируется до получения результата

      // Метод get может генерировать проверенные исключения

      // например, когда это прерывается. Это причина

      // для добавления предложения throws в main

    }

  }

}

Выход:

4
2
3
3
0

Все взаимодействие с потоком после его запуска использует объект FutureTask, поскольку он реализует интерфейс Future. Следовательно, нет необходимости хранить объекты Thread. Используя объект FutureTask, можно отменить задачу, проверить ее выполнение или попытаться получить результат.

Вот код, использующий только Runnable.

// Java-программа для иллюстрации Runnable
// для генерации случайных чисел

import java.util.Random;

import java.util.concurrent.Callable;

import java.util.concurrent.FutureTask;

  

class RunnableExample implements Runnable

{

    // Общий объект для сохранения результата

    private Object result = null;

  

    public void run()

    {

        Random generator = new Random();

        Integer randomNumber = generator.nextInt(5);

  

        // Поскольку run не может выдать исключение

        try

        {

            Thread.sleep(randomNumber * 1000);

        }

        catch (InterruptedException e)

        {

            e.printStackTrace();

        }

  

        // Сохраняем возвращаемое значение в результате, когда закончим

        result = randomNumber;

  

        // Пробуждение потоков, заблокированных в методе get ()

        synchronized(this)

        {

            notifyAll();

        }

    }

  

    public synchronized Object get()

          throws InterruptedException

    {

        while (result == null)

            wait();

  

        return result;

    }

}

  
// Код почти такой же, как в предыдущем примере с
// сделано несколько изменений для использования Runnable вместо Callable

public class RunnableTest

{

    public static void main(String[] args) throws Exception

    {

        RunnableExample[] randomNumberTasks = new RunnableExample[5];

  

        for (int i = 0; i < 5; i++)

        {

            randomNumberTasks[i] = new RunnableExample();

            Thread t = new Thread(randomNumberTasks[i]);

            t.start();

        }

  

        for (int i = 0; i < 5; i++)

            System.out.println(randomNumberTasks[i].get());

    }

}

Пример вывода

0
4
3
1
4
2

Ссылки

Эта статья предоставлена Сиддхартом Сундаром . Если вы как GeeksforGeeks и хотели бы внести свой вклад, вы также можете написать статью с помощью contribute.geeksforgeeks.org или по почте статьи contribute@geeksforgeeks.org. Смотрите свою статью, появляющуюся на главной странице GeeksforGeeks, и помогите другим вундеркиндам.

Пожалуйста, пишите комментарии, если вы обнаружите что-то неправильное или вы хотите поделиться дополнительной информацией по обсуждаемой выше теме.

Рекомендуемые посты:

Callable и будущее в Java

0.00 (0%) 0 votes