我正在阅读“使用JAX-RS 2.0的RESTful Java”一书。我完全混淆了异步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
对象将与某些后台作业共享,并在准备就绪时向所有客户端发送报价。
我的问题:
答案 0 :(得分:9)
执行摘要:你过度思考了这一点。
在示例1和2中,Web服务器线程(处理请求的线程)死亡,我们创建另一个后台线程。异步服务器背后的整个想法是减少空闲线程。这些示例不会减少空闲线程。一个线程死亡,另一个线程死亡。
说实话,两者都不是特别好。在生产服务中,您不会将执行程序保存在这样的私有字段中,而是将其作为单独配置的对象(例如,它自己的Spring bean)。另一方面,如果没有更多的背景,这样一个复杂的例子对你来说更难理解;由bean /托管资源系统组成的应用程序必须从头开始构建。对于小规模的工作而言,对此非常谨慎并不是很重要,而且这是很多的Web应用程序。
The gripping hand是从服务器重启恢复实际上并不是首先要担心的事情。如果服务器重新启动,您可能会丢失所有连接,如果这些AsyncResponse
对象在某种程度上不是Serializable
(不保证它们是否存在),则不能将它们存储在数据库中以启用恢复。最好不要担心太多,因为你没有太多可以做的! (如果他们没有得到任何回复,客户也会在一段时间后超时;你不能无限期地持有它们。)
我认为在容器内创建非托管线程是个坏主意。我们应该只在Java EE 7中使用并发实用程序来使用托管线程。
这是一个例子!无论您想要什么样的生产系统,都可以从外部提供执行器。
异步服务器背后的一个想法是扩展。例3没有缩放,是吗?
它只是将列表中的对象排入队列,这根本不是一个非常慢的操作,特别是与所有网络和反序列化/序列化的成本相比时。它没有显示的是应用程序的其他部分,它从列表中取出,执行处理并返回结果;它们可能执行不力并导致问题,或者它们可以小心地完成并且系统运行良好。
如果您可以在代码中做得更好,一定要这样做。 (请注意,您无法将工作项存储在数据库中,或者至少您无法确定您是否可以这样做,即使它实际上是可行的。但我对此表示怀疑;可能存在信息关于那里的TCP网络连接,这绝不容易完全存储和恢复。)
答案 1 :(得分:0)
我分享你在问题1中表达的观点。让我简单地添加一个网络服务器线程不会死的细节,它通常来自一个池,并为另一个Web请求释放自己。但就异步处理的效率而言,这并没有太大改变。在这些示例中,异步处理仅用于将处理从一个线程池传递到另一个线程池。我完全没有看到任何意义。
但有一个用例,我认为异步是有意义的,例如。当您想要注册多个客户端以等待事件时,并在事件发生后向所有客户端发送响应。本文对此进行了描述:http://java.dzone.com/articles/whats-new-jax-rs-20
答案 2 :(得分:0)
如果不同的线程池管理请求I / O和请求处理,则服务的吞吐量会提高。释放由容器管理的请求I / O线程允许它接收下一个请求,准备处理并在请求处理线程释放时将其提供给请求处理线程池。