码迷,mamicode.com
首页 > 其他好文 > 详细

Servlet3.0对异步处理的支持

时间:2019-10-03 23:54:46      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:其它   线程   做了   被占用   使用   私有   lock   生成   接口   

Servlet工作流程

Servlet 3.0 之前,一个普通 Servlet 的主要工作流程大致如下:

  1. Servlet 接收到请求之后,可能需要对请求携带的数据进行一些预处理;
  2. 调用业务接口的某些方法,以完成业务处理;
  3. 最后,根据处理的结果提交响应,Servlet 线程结束。

技术图片

servlet是单例多线程的,当servlet线程池满了的时候,后续访问该Servlet的请求只能进行等待

其中第二步的业务处理通常是最耗时的,这主要体现在数据库操作,以及其它的跨网络调用等,在此过程中,Servlet 线程一直处于阻塞状态,直到业务方法执行完毕。在处理业务的过程中,Servlet 资源一直被占用而得不到释放,对于并发较大的应用,这有可能造成性能的瓶颈。对此,在以前通常是采用私有解决方案来提前结束 Servlet 线程,并及时释放资源。

Servlet3.0异步处理

Servlet 3.0 针对这个问题做了开创性的工作,现在通过使用 Servlet 3.0 的异步处理支持,之前的 Servlet 处理流程可以调整为如下的过程:

  1. 首先,Servlet 接收到请求之后,可能首先需要对请求携带的数据进行一些预处理;
  2. 接着,Servlet 线程将请求转交给一个异步线程来执行业务处理,线程本身返回至容器,此时 Servlet 还没有生成响应数据,异步线程处理完业务以后,可以直接生成响应数据(异步线程拥有 ServletRequest 和 ServletResponse 对象的引用),或者将请求继续转发给其它 Servlet。如此一来, Servlet 线程不再是一直处于阻塞状态以等待业务逻辑的处理,而是启动异步线程之后可以立即返回。

代码示例一:

首先创建一个动态的web工程

技术图片

public class DemoThread implements Runnable {
    private PrintWriter out;

    public DemoThread(PrintWriter out) {
        this.out = out;
    }

    @Override
    public void run() {
        out.println("子线程---运行<br>");
        int sum = 0;
        for (int i = 0; i < 10; i++) {
            System.out.println("i = " + i);
            sum += i;
            try {
                Thread.sleep(1000L);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        out.println("sum = " + sum + "<br>");
        out.println("子线程---结束<br>");
    }
}
@WebServlet("/demo")
public class DemoServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.print("主线程开始运行<br>");
        new Thread(new DemoThread(out)).start();
        out.print("主线程运行结束<br>");
    }
}

使用Servelt3.0注解方式创建的一个DemoServlet,我们运行tomcat容器并访问这个Servlet

技术图片

观察控制台:

技术图片

这与我们需要的展示效果相差甚远 :主线程直接就结束了,子线程依旧在运行


注意:

异步处理特性可以应用于 Servlet 和过滤器两种组件,由于异步处理的工作模式和普通工作模式在实现上有着本质的区别,因此默认情况下,Servlet 和过滤器并没有开启异步处理特性,如果希望使用该特性,则必须按照如下的方式启用:

我们开启Servelt异步处理后,改写代码观察结果:

// asyncSupported 默认为false,
@WebServlet(value = "/demo",asyncSupported = true)
public class DemoServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.println("进入Servlet的时间:" + new Date() + "<br>");

        //在子线程中执行业务调用,并由其负责输出响应,主线程退出
        AsyncContext ctx = request.startAsync();
        new Thread(new DemoThread(ctx)).start();
        out.println("结束Servlet的时间:" + new Date() + "<br>");
    }
}
public class DemoThread implements Runnable {

    private AsyncContext ctx = null;

    public DemoThread(AsyncContext ctx) {
        this.ctx = ctx;
    }

    @Override
    public void run() {
        int sum = 0;
        try {
            // 通过此种方式就能获取到响应流
            PrintWriter out = ctx.getResponse().getWriter();
            out.println("子线程---运行<br>");
            sum = 0;
            for (int i = 0; i < 10; i++) {
                System.out.println("i = " + i);
                sum += i;
                Thread.sleep(1000L);
            }
            out.println("sum = " + sum + "<br>");
            out.println("子线程---结束<br>");
            out.println("业务处理完毕的时间:" + new Date() + "<br>");
            ctx.complete();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

技术图片

观察时间可以发现,Servlet线程运行完就结束了,返回到线程池,大大节省了资源,如果有多个请求,就能够处理接下来的请求。而我们的DemoThread线程依旧能够生成响应数据

Servlet3.0对异步处理的支持

标签:其它   线程   做了   被占用   使用   私有   lock   生成   接口   

原文地址:https://www.cnblogs.com/heliusKing/p/11620958.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!