Какова цель асинхронного JAX-RS
Я читаю книгу "RESTful Java с JAX-RS 2.0". Я полностью запутался с асинхронным JAX-RS, поэтому я задаю все вопросы в одном. Книга пишет асинхронный сервер так:
@Path("/customers")
public class CustomerResource {
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_XML)
public void getCustomer(@Suspended final AsyncResponse asyncResponse,
@Context final Request request,
@PathParam(value = "id") final int id) {
new Thread() {
@Override
public void run() {
asyncResponse.resume(Response.ok(new Customer(id)).build());
}
}.start();
}
}
Netbeans создает асинхронный сервер следующим образом:
@Path("/customers")
public class CustomerResource {
private final ExecutorService executorService = java.util.concurrent.Executors.newCachedThreadPool();
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_XML)
public void getCustomer(@Suspended final AsyncResponse asyncResponse,
@Context final Request request,
@PathParam(value = "id") final int id) {
executorService.submit(new Runnable() {
@Override
public void run() {
doGetCustomer(id);
asyncResponse.resume(javax.ws.rs.core.Response.ok().build());
}
});
}
private void doGetCustomer(@PathParam(value = "id") final int id) {
}
}
Те, которые не создают фоновые потоки, используют некоторые методы блокировки для хранения объектов ответа для дальнейшей обработки. Этот пример для отправки котировок акций клиентам:
@Path("qoute/RHT")
public class RHTQuoteResource {
protected List<AsyncResponse> responses;
@GET
@Produces("text/plain")
public void getQuote(@Suspended AsyncResponse response) {
synchronized (responses) {
responses.add(response);
}
}
}
responses
Объект будет доступен для некоторых фоновых заданий и отправит цитату всем клиентам, когда будет готов.
Мои вопросы:
- В примере 1 и 2 поток веб-сервера (тот, который обрабатывает запрос) умирает, и мы создаем другой фоновый поток. Вся идея асинхронного сервера состоит в том, чтобы уменьшить количество неиспользуемых потоков. Эти примеры не сокращают количество неиспользуемых потоков. Одна нить умирает, а другая рождается.
- Я думал, что создание неуправляемых потоков внутри контейнера - плохая идея. Мы должны использовать только управляемые потоки, используя утилиты параллелизма в Java EE 7.
- Опять же, одна из идей асинхронных серверов - масштабирование. Пример 3 не масштабируется, не так ли?
3 ответа
Резюме: Вы слишком обдумываете это.
В примере 1 и 2 поток веб-сервера (тот, который обрабатывает запрос) умирает, и мы создаем другой фоновый поток. Вся идея асинхронного сервера состоит в том, чтобы уменьшить количество неиспользуемых потоков. Эти примеры не сокращают количество неиспользуемых потоков. Одна нить умирает, а другая рождается.
Если честно, ни то, ни другое не особенно здорово. В производственном сервисе вы бы не держали исполнителя в таком закрытом поле, а вместо этого имели бы его как отдельно сконфигурированный объект (например, свой собственный Spring bean-компонент). С другой стороны, такой сложный пример будет довольно сложным для понимания без более широкого контекста; приложения, которые состоят из систем bean / управляемых ресурсов, должны создаваться таким образом с нуля. Также для мелкомасштабной работы не очень важно быть очень осторожным с этим, и это много веб-приложений.
Захватывающая рука заключается в том, что восстановление после перезапуска сервера на самом деле не является чем-то, о чем нужно беспокоиться в первую очередь. Если сервер перезапустится, вы все равно потеряете все соединения, и если AsyncResponse
объекты не Serializable
каким-то образом (без гарантии, что они есть или нет), вы не можете сохранить их в базе данных, чтобы включить восстановление. Лучше не беспокоиться об этом слишком много, так как мало что можно сделать! (Клиенты также собираются через некоторое время, если они не получают никакого ответа; вы не можете удерживать их бесконечно.)
Я думал, что создание неуправляемых потоков внутри контейнера - плохая идея. Мы должны использовать только управляемые потоки, используя утилиты параллелизма в Java EE 7.
Это пример! Поставьте исполнителя со стороны, как вы хотите, для вашей необычной производственной системы.
Опять же, одна из идей асинхронных серверов - масштабирование. Пример 3 не масштабируется, не так ли?
Это просто помещение объекта в список, что вовсе не очень медленная операция, особенно по сравнению со стоимостью всей работы в сети и десериализации / сериализации. То, что он не показывает, это другие части приложения, которые убирают вещи из этого списка, выполняют обработку и возвращают результат; они могут быть плохо реализованы и вызывать проблемы, или они могут быть выполнены осторожно, и система будет работать хорошо.
Если вы можете сделать это лучше в своем коде, сделайте это во что бы то ни стало. (Просто знайте, что вы не можете хранить рабочие элементы в базе данных, или, по крайней мере, вы не можете точно знать, что можете это сделать, даже если это действительно возможно. Хотя я сомневаюсь в этом; есть вероятная информация о сетевом соединении TCP там, и это никогда не легко хранить и восстанавливать полностью.)
Пропускная способность службы улучшается, если разные пулы потоков управляют вводом-выводом и обработкой запросов. Освобождение потока запроса-ввода-вывода, управляемого контейнером, позволяет ему получить следующий запрос, подготовить его к обработке и передать в поток обработки запроса при освобождении потока обработки запроса.
Я разделяю ваше мнение, выраженное в вопросе 1. Позвольте мне добавить небольшую деталь, что поток веб-сервера не умирает, он обычно исходит из пула и освобождает себя для другого веб-запроса. Но это не сильно меняет с точки зрения эффективности асинхронной обработки. В этих примерах асинхронная обработка просто используется для передачи обработки из одного пула потоков в другой. Я не вижу в этом никакого смысла.
Но есть один вариант использования, где я думаю, что асинхронность имеет смысл, например. когда вы хотите зарегистрировать несколько клиентов, чтобы дождаться события и отправить ответ всем им, как только событие произойдет. Это описано в этой статье: http://java.dzone.com/articles/whats-new-jax-rs-20