Какова цель асинхронного 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. В примере 1 и 2 поток веб-сервера (тот, который обрабатывает запрос) умирает, и мы создаем другой фоновый поток. Вся идея асинхронного сервера состоит в том, чтобы уменьшить количество неиспользуемых потоков. Эти примеры не сокращают количество неиспользуемых потоков. Одна нить умирает, а другая рождается.
  2. Я думал, что создание неуправляемых потоков внутри контейнера - плохая идея. Мы должны использовать только управляемые потоки, используя утилиты параллелизма в Java EE 7.
  3. Опять же, одна из идей асинхронных серверов - масштабирование. Пример 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

Другие вопросы по тегам