Статьи

Учебник по параллелизму Java — вызываемое, будущее

Одна из замечательных особенностей Java с самого ее первого выпуска заключалась в том, что мы могли с легкостью писать многопоточные программы и внедрять асинхронную обработку в наши проекты. Класс Thread и интерфейс Runnable в сочетании с моделью управления памятью Java предназначены для простого программирования потоков. Но, как обсуждалось в Части 3 , ни класс Thread, ни интерфейс Runnable не допускали выдачи исключений или возвращаемых значений. Отсутствие возвращаемых значений было немного раздражающим.

Отсутствие брошенных проверенных исключений было немного серьезнее. Контракт был публичным void run (), что означало, что вы должны отлавливать проверенные исключения и что-то с ними делать. Даже если вы были осторожны и сохранили их для последующей проверки, вы не можете заставить все использования класса проверить исключение. Вы можете пройти через все свои методы получения и выбросить Исключение, если оно существует на каждом. Помимо громоздкости, даже это не было надежным. Вы не можете навязать звонки ни одному из них. Программисты потоков правильно вызвали бы join (), чтобы дождаться его завершения, и, возможно, затем пошли своим путем.

Не волнуйтесь, хотя, спустя много лет, это было наконец решено в версии 1.5. С появлением интерфейсов Callable и Future и их поддержкой в ​​пулах потоков, обсуждаемых в нашем последнем посте, обе эти проблемы были решены довольно элегантно.

подлежащий выкупу

Интерфейс Callable объявляет, что публичный вызов T () генерирует Exception . Теперь мы можем вернуть результат, строго его типизировать, как объявлено в нашей реализации, и даже выдать исключения . Несмотря на то, что в классе Executors есть несколько служебных методов для преобразования ваших экземпляров Runnable, как обсуждалось в части 3 , было бы неплохо рассмотреть ваши текущие реализации Runnable или подклассов Thread . Зачем беспокоиться? Прежде всего, дважды проверьте и удалите обходной путь, который вы, возможно, применили для решения проблемы отсутствия брошенных исключений . В то же время вы можете использовать возможность возвращать результаты прямо в методе выполнения, что устраняет необходимость в приведении для получения значений.

Будущее

Вот где объединяются мощь пулов потоков и Callable . Будущее — это еще один новый интерфейс, представленный в 1.5. Когда вы отправляете Callable в один из пулов потоков, вам предоставляется экземпляр Future, который напечатан для Callable, который вы передали. Этот объект заменяет реальный экземпляр Thread, который вы использовали бы до 1.5. Если раньше вам приходилось выполнять Thread.join () или Thread.join (long millis) , то теперь вы можете использовать их, как в этом примере.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class ServerAcceptingRequestsVerifier implements Callable {
    /**
     * @return Boolean.TRUE is server is accepting requests
     * Boolean.FALSE otherwise
     */
    public Boolean call() throws Exception {
        Boolean isAcceptingRequests = null;
        ... ask server about taking requests here
        return isAcceptingRequests;
    }
}
public Boolean isServerTakingRequests(String server)
            throws UnresponsiveException, InterruptedException {
    ServerAcceptingRequestsVerifier acceptingRequestsVerifier =
        new ServerAcceptingRequestsVerifier();
    Future future =
        THREAD_POOL.submit(acceptingRequestsVerifier);
    try {
        Boolean isAcceptingRequests = future.get();
        //waits for the thread to complete, even if it hasn't started
        return isAcceptingRequests;
    } catch (ExecutionException e) {
        throw new UnresponsiveException(e.getCause());
    }
 
}

Также хорошо, что теперь у нас есть явное исключение TimeoutException, если мы решаем ограничить продолжительность ожидания завершения.

01
02
03
04
05
06
07
08
09
10
11
12
try {
    Boolean isAcceptingRequests = future.get(5, TimeUnit.SECONDS);
    //this waits for 5 seconds, throwing TimeoutException if not done
    return isAcceptingRequests;
} catch (TimeoutException e) {
    LOGGER.warn("Timed out waiting for server check thread." +
        "We'll try to interrupt it.");
    future.cancel(true);
    return Boolean.FALSE;
} catch (ExecutionException e) {
    throw new UnresponsiveException(e.getCause());
}

В нашей следующей статье мы познакомимся с некоторыми новыми интерфейсами / классами, которые используются для работы пулов потоков, которые также доступны для нашего использования.

Ссылка: Java Concurrency Part 4 — Callable, Future от наших партнеров JCG в блоге Carfey Software .

Статьи по Теме :