java servlet异步_Servlet的异步和非堵塞

本文详细介绍了Java Servlet中的异步处理和非堵塞I/O。通过示例展示了如何利用AsyncContext启动异步任务,并使用ScheduledThreadPoolExecutor执行长时间运行的服务。同时,解释了Servlet 3.1中的非堵塞I/O,包括ReadListener和WriteListener的使用,以实现更高的并发性和服务器可扩展性。
摘要由CSDN通过智能技术生成

Servlet的异步和非堵塞

Asynchronous异步

服务器资源是有价值的,应谨慎使用。考虑一个servlet

必须等待一个JDBC连接,或等待接收JMS消息

或从文件系统读取的资源。等待一个“长期运行”过程返回会引起

线程完全阻塞。异步

处理在在等待长时间运行的过程同时,可以使控制(或线程)返回到容器来继续执行其他

任务。

@WebServlet(urlPatterns="/async", asyncSupported=true)

public class MyAsyncServlet extends HttpServlet {

也可以在 web.xml定义为true。

然后,您可以在单独的线程使用request的同步放startA方法启动异步处理

,此方法返回AsyncContext,它代表了

异步请求的执行上下文。然后你就可以通过调用AsyncContext.complete完成异步

,或者派遣到另一个请求

资源(隐式)。容器将在后台完成异步请求的调用。

假设有一个需要长时间运行的任务:

class MyAsyncService implements Runnable {

AsyncContext ac;

public MyAsyncService(AsyncContext ac) {

this.ac = ac;

}

@Override

public void run() {

//. . .

ac.complete();

}

}

这个任务可以在servlet中被调用异步运行:

@Override

protected void doGet(HttpServletRequest request,

HttpServletResponse response) {

AsyncContext ac = request.startAsync();

ac.addListener(new AsyncListener() {

public void onComplete(AsyncEvent event)

throws IOException {

//. . .

}

public void onTimeout(AsyncEvent event)

throws IOException {

//. . .

}

//. . .

});

ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);

executor.execute(new MyAsyncService(ac));

}

该请求被放入异步模式。 当请求处理完成后,AsyncListener被注册

侦听事件,或已超时,或导致一个错误。长期运行的服务在一个单独的线程异步调用,完成请求处理调用Context.complete。

非堵塞Nonblocking I/O

Servlet 3.0中允许异步请求处理,但只允许传统

I / O,这限制了应用程序的可扩展性。

protected void doGet(HttpServletRequest request, HttpServletResponse response)

throws IOException, ServletException {

ServletInputStream input = request.getInputStream();

byte[] b = new byte[1024];

int len = -1;

while ((len = input.read(b)) != -1) {

//. . .

}

}

如果传入的数据流比服务器更慢,那么

服务器线程就在等待数据。如果数据被写入,相同的可能也会发生,这限制了Web容器的可扩展性。

非阻塞I / O使得Web容器不仅可伸缩,也可以同时处理更多连接数量。非阻塞

I / O只能用异步请求处理的Servlet,过滤器。Servlet3.1实现了非阻塞I / O,通过引入两个新的接口:ReadListener和WriteListener。这些监听者有回调方法,可以在

内容可被读取或可写入而不阻塞时调用。前面案例重写为:

AsyncContext context = request.startAsync();

ServletInputStream input = request.getInputStream();

input.setReadListener(new MyReadListener(input, context));

ReadListener有三个回调方法:

onDataAvailable回调方法是数据可以被读取时调用

onAllDataRead回调方法是当请求数据

完全读取时调用。

OnError回调是如果有一个错误处理请求时被调用

@Override

public void onDataAvailable() {

try {

StringBuilder sb = new StringBuilder();

int len = -1;

byte b[] = new byte[1024];

while (input.isReady() && (len = input.read(b)) != -1) {

String data = new String(b, 0, len);

}

} catch (IOException ex) {

//. . .

}

}

@Override

public void onAllDataRead() {

context.complete();

}

@Override

public void onError(Throwable t) {

t.printStackTrace();

context.complete();

}

ServletInputStream.isReady方法用于检查数据可以被读取而不会阻塞,然后数据被读出。 context.complete在

onAllDataRead和onError方法读取数据的完成后调用。 Servle

tInputStream.isFinished可以用来检查一个非阻塞I/ O读取的状态。

WriteListener有两个回调方法:

onWritePossible是可以无堵塞写入数据被调用时

onerror的是如果有错误处理响应时被调用

最多只有一个WriteListener可以在ServletOutputStream注册。 ServletOut

putStream.canWrite是一种新的方法检查数据是否可以不阻塞地被写入。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值