Подтвердить что ты не робот

Какова цель AsyncContext.start(...) в Servlet 3.0?

API-интерфейс сервлета говорит об "AsyncContext.start":

void start (java.lang.Runnable run)

Заставляет контейнер отправлять поток, возможно из пула управляемых потоков, для запуска указанного Runnable. Контейнер может распространять соответствующую контекстуальную информацию на Runnable.

Из этого описания неясно, как оно относится к задаче оптимизации использования потока, когда задание требует ожидания.

В "Сервлетах и ​​JSP" Budi Kurniawan дает пример асинхронных функций Servlet 3.0, где он использует AsyncContext.start, я покажу упрощенную версию примера:

public void doGet(...) {
    final AsyncContext asyncContext = request.startAsync();

    asyncContext.start(new Runnable() {                        
        @ Override
        public void run() {
            // do some work here which involves waiting
            ...
            asyncContext.complete();
        }
    });
}

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

Вы действительно что-то получаете, передавая работу (которая включает в себя ожидание) из одного потока в другой? Если нет, то какая цель AsyncContext.start(...)?

4b9b3361

Ответ 1

Вы нашли плохой пример, ИМХО. На самом деле я даже не знал о AsyncContext.start() существования.

Я быстро посмотрел, как Jetty и Tomcat реализовать это. На самом деле у них, похоже, есть пул потоков, который обрабатывает асинхронные вызовы независимо.

Такое использование API дает вам ничего или очень мало. Вместо блокировки потока HTTP вы блокируете другой пул потоков. Поэтому я могу представить, что приложение по-прежнему принимает новые подключения, но проблема остается - контейнер не может справиться с ними, потому что этот дополнительный пул потоков по-прежнему ограничен.

Все точки AsyncContext - это возможность обрабатывать несколько запросов одним потоком. Часто для обработки тысяч асинхронных подключений требуется только один поток. когда ровно один поток ожидает данных, которые предполагается транслировать нескольким клиентам. Также см. Ограниченная полезность AsyncContext.start()

Ответ 2

Сначала у меня была такая же реакция - если вы просто передаете работу в другой поток, что вы получаете? Спецификация не очень помогает объяснить, почему это хорошая идея. Но этот пост отлично справляется. В принципе, это позволяет серверу грамотно деградировать под большой нагрузкой, а не просто терпеть неудачу, заканчивая потоками. Фактическая работа выполняется в пуле потоков фиксированного размера, поэтому сервер может принимать любое количество запросов без необходимости поддерживать поток вокруг каждого из них до его завершения. Конечно, вам может потребоваться настроить настройки O/S, чтобы иметь возможность открывать тысячи сокетов одновременно.

Как только у вас есть эта возможность, вы можете более легко использовать архитектуру Comet (server push), где клиентский Javascript сохраняет запрос AJAX открытым, чтобы сервер мог уведомить об этом, как только произойдет какое-то событие, а не опросить сервер, чтобы узнать, произошло ли что-то.

Ответ 3

Одна из причин, по которой это может быть полезно, - это когда вы хотите освободить входящий веб-поток, выполнить какую-то другую работу, а после завершения - вернуться к веб-потоку (может быть, еще один поток, но все же из пула веб-сервера), чтобы завершить первоначальную операцию и отправить ответ клиенту.

Например:

1. ac = request.startAsync();
2. forward("some data", "another system"); // async outbound HTTP request
3. (at this point, incoming servlet thread is released to handle other requests)
4. (in some other, non-servlet thread, upon "forward" response arrival)
   ac.start(new Runnable() { /* send response to the client */ });

Вы могли бы, конечно, отправить ответ в поток без сервлета, но это имеет один недостаток: вы используете поток без сервлета для выполнения типичных операций с сервлетами, что означает, что вы неявно изменяете баланс между количеством потоков мощность, зарезервированная для работы сервлетов, и другая работа.

Другими словами - он дает вам возможность отправлять Runnable в пул потоков сервлета. Очевидно, что это редкие потребности, но все же - это дает некоторые аргументы в пользу метода AsyncContext.start().

Ответ 4

Tomcat ThreadPoolExecutor на основе java.util.concurrent.ThreadPoolExecutor и настроен в Apache Tomcat 8 Справочник по настройке. Он обрабатывает весь запрос Tomcat, поэтому, если у вас есть работа с длительным сроком, лучше обработать их в собственном малогабаритном пуле фиксированных/кэшированных потоков и отправить задание типа описанное здесь.