服务器资源是有价值的,应谨慎使用。考虑一个servlet 必须等待一个JDBC链接,或等待接收JMS消息 或从文件系统读取的资源。等待一个“长期运行”过程返回会引发 线程彻底阻塞。异步
处理在在等待长时间运行的过程同时,能够使控制(或线程)返回到容器来继续执行其余
任务。php
@WebServlet(urlPatterns="/async",asyncSupported=true)
public class MyAsyncServlet extends HttpServlet {html
}java
也能够在 web.xml定义<async-supported>为true。web
也能够在 web.xml定义<async-supported>为true。服务器
而后,您能够在单独的线程使用request的同步放startA方法启动异步处理
,此方法返回AsyncContext,它表明了 异步请求的执行上下文。而后你就能够经过调用AsyncContext.complete完成异步 ,或者派遣到另外一个请求 资源(隐式)。容器将在后台完成异步请求的调用。异步
假设有一个须要长时间运行的任务:async
class MyAsyncService implements Runnable {
AsyncContext ac;
public MyAsyncService(AsyncContext ac) {
this.ac = ac;
}
@Override
public void run() {
//. . .
ac.complete();
}
}ide
这个任务能够在servlet中被调用异步运行:ui
@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 {
//. . .
}
//. . .
});this
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);
executor.execute(new MyAsyncService(ac));
}
该请求被放入异步模式。 当请求处理完成后,AsyncListener被注册 侦听事件,或已超时,或致使一个错误。长期运行的服务在一个单独的线程异步调用,完成请求处理调用Context.complete。
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是一种新的方法检查数据是否能够不阻塞地被写入。