收藏already右耳菌-邓小白的Java架构师的修炼之路

Web容器中的异步处理

2022-06-23  本文已影响0人  右耳菌

Servlet 3.x 概述

在Servlet 3.0之前,Servlet采用Thread-Per-Request的方式处理请求,即每一次Http请求都由某一个线程从头到尾负责处理。如果一个请求需要进行I0操作,比如访问数据库、调用第三方服务接口等,那么其所对应的线程将同步地等待lO操作完成,而IO操作是非常慢的,所以此时的线程并不能及时地释放回线程池以供后续使用,在并发量越来越大的情况下,这将带来严重的性能问题。

Servlet3.x 的新特性
例子
package com.study.servletdemo.servletDemo;

import com.study.servletdemo.dosomthing.DoSomThingRunning;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@WebServlet("/test")
public class Servlet4Sync1 extends HttpServlet {


    private static ThreadPoolExecutor executor =
            new ThreadPoolExecutor(100, 200, 5000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(200));

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //TODO 这里面写逻辑
        System.out.println("当前处理请求的线程是:" + Thread.currentThread().getName());
        new DoSomThingRunning().run(); //调用一个方法.
        resp.getWriter().write("OK,get a response");
    }
}
package com.study.servletdemo.servletDemo;

import com.study.servletdemo.dosomthing.DoSomThingRunning;

import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@WebServlet(value = "/test1", asyncSupported = true)
public class ServletSync2 extends HttpServlet {

    private static ThreadPoolExecutor executor =
            new ThreadPoolExecutor(100, 200, 5000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(200));

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        AsyncContext asyncContext = req.startAsync(); //实现异步机制
        System.out.println("当前运行的Thread:" + Thread.currentThread().getName());
        executor.execute(() -> {
            new DoSomThingRunning().run();
            try {
                asyncContext.getResponse().getWriter().write("ok,is response");
            } catch (IOException e) {
                e.printStackTrace();
            }
            asyncContext.complete();
        });
// 非线程池的方式
//         asyncContext.start(()->{
//             new DoSomThingRunning().run();
//             try {
//                 asyncContext.getResponse().getWriter().write("ok,is response");
//             } catch (IOException e) {
//                 e.printStackTrace();
//             }
//             asyncContext.complete();
//         });
    }
}

DeferredResult 异步处理

在SpringMVC中,基于Servlet3.x的异步特性,Spring也提供了一套异步处理的方案。基于DeferredResult来实现异步处理。

DeferredResult的主要流程:
DeferredResult处理流程
DeferredResult 的例子

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@RestController
public class DeferredResultController {

    private LinkedBlockingQueue<DeferredResult> queue = new LinkedBlockingQueue<>();

    ThreadPoolExecutor executor =
            new ThreadPoolExecutor(1000, 1500, 5000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(200));

    @RequestMapping("/get")
    public DeferredResult<String> getResult() {
        final DeferredResult<String> stringDeferredResult = new DeferredResult<>(3000L); //

        queue.add(stringDeferredResult);

        executor.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    Random random = new Random();
                    int time = random.nextInt(5000);
                    System.out.println("休眠时间:" + time);
                    Thread.sleep(time);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //处理业务的代码
                System.out.println("处理业务");
                String rs = "返回值...";
                stringDeferredResult.setResult(rs);
            }
        });

        stringDeferredResult.onTimeout(new Runnable() { //超时之后执行...
            @Override
            public void run() {
                //TODO --自己的业务
                System.out.println("超时处理...");
                stringDeferredResult.setResult("超时的返回结果");
            }
        });

        stringDeferredResult.onCompletion(new Runnable() {
            @Override
            public void run() {
                System.out.println("任务完成了..把队列中的deferredRueslt移除");
                queue.remove();
            }
        });

        return stringDeferredResult;

    }

    @Scheduled(fixedRate = 1000)
    public void scheduleResult() {
        for (int i = 0; i < queue.size(); i++) {
            DeferredResult<String> stringDeferredResult = queue.poll();
            stringDeferredResult.setResult("result:" + i);
        }
    }

}
总结

如果觉得有收获就点个赞吧,更多知识,请点击关注查看我的主页信息哦~

上一篇 下一篇

猜你喜欢

热点阅读