一尘不染

异步JAX-RS的目的是什么

java

我正在阅读“ RESTful Java with 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中,Web服务器线程(处理请求的线程)死亡,我们创建了另一个后台线程。异步服务器背后的整个想法是减少空闲线程。这些示例没有减少空闲线程。一个线程死亡,另一个线程出生。
  2. 我认为在容器内创建非托管线程是一个坏主意。我们仅应在Java EE 7中使用并发实用程序来使用托管线程。
  3. 同样,异步服务器背后的想法之一就是扩展规模。示例3无法缩放,是吗?

阅读 279

收藏
2020-12-03

共1个答案

一尘不染

内容提要: 您对此考虑过多。


在示例1和2中,Web服务器线程(处理请求的线程)死亡,我们创建了另一个后台线程。异步服务器背后的整个想法是减少空闲线程。这些示例没有减少空闲线程。一个线程死亡,另一个线程出生。

老实说,这两者都不是特别棒。在生产服务中,您不会将执行程序保留在这样的私有字段中,而是将其作为单独配置的对象(例如,其自己的Spring
bean)。另一方面,如果没有更多上下文,那么这样一个复杂的示例将使您难以理解。包含bean
/受管资源系统的应用程序必须从头开始构建。对于小规模的工作,要特别注意这一点也不是很重要,这是 很多 Web应用程序。

令人抓紧的是,首先不必担心从服务器重新启动进行恢复。如果服务器重新启动,您可能仍然会丢失所有连接,并且如果这些AsyncResponse对象不是Serializable以某种方式(不能保证它们是或不是),则无法将它们存储在数据库中以进行恢复。最好不要担心太多,因为您无能为力!(如果客户还没有收到任何回复,他们也会在一段时间后超时;您不能无限期地等待他们。)

我认为在容器内创建非托管线程是一个坏主意。我们仅应在Java EE 7中使用并发实用程序来使用托管线程。

这是一个例子!从外部为执行机构生产所需的执行器。

同样,异步服务器背后的想法之一就是扩展规模。示例3无法缩放,是吗?

它只是将一个对象排入列表,这根本不是一个很慢的操作,尤其是与进行所有网络连接和反序列化/序列化的成本相比时。它没有显示的是应用程序的其他部分,这些部分将列表中的内容去除,执行处理并将结果返回;它们可能实施不当并导致问题,或者可以仔细完成并且系统运行良好。

如果您可以在代码中做得更好, 则一定要这样做
。(请注意,您无法将工作项存储在数据库中,或者至少无法确定您是否可以做到这一点,即使它确实有可能。我对此表示怀疑;但可能会有信息有关其中的TCP网络连接的信息,而要完全存储和恢复它绝非易事。)

2020-12-03