Servlet异步非阻塞IO处理

简述

Servlet3.0提供异步功能,Servlet3.1提供非阻塞IO功能。

使用异步,能快速释放Servlet容器线程池的线程,异步任务交由业务线程池来处理。

开始


import javax.servlet.*;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Date;
import java.util.concurrent.*;

/**
 * @program: demo->MysTest
 * @description:
 * @author: liangshijie
 * @create: 2020-10-10 16:52
 **/
@WebServlet(urlPatterns = "/",  asyncSupported = true)
public class MysTest extends HttpServlet {

    /**
     * 有效核心处理器
     */
    private final static int AVALIABLE_PROCESSORS = Runtime.getRuntime().availableProcessors();
    /**
     * 核心线程数
     */
    private final static int CORE_POOL_SIZE = AVALIABLE_PROCESSORS;
    /**
     * 最大线程数
     */
    private final static int MAX_IMUM_POOL_SIZE = AVALIABLE_PROCESSORS * 2;
    /**
     * 线程保存时间
     */
    private final static long KEEP_LIVE_TIME = 1L;

    /**
     * 核心线程数及队列满了,就会新建线程
     */
    private final static BlockingQueue<Runnable> WORK_QUEUE = new ArrayBlockingQueue<>(5);

    /**
     * 线程工程,可以指定线程名字以区分业务
     */
    private final static ThreadFactory THREAD_FACTORY = new TaskThreadFactory();

    /**
     * 策略
     */
    private final static RejectedExecutionHandler  HANDLER = new ThreadPoolExecutor.CallerRunsPolicy();

    /**
     *
     RejectedExecutionHandler handler;
     1.抛出异常(默认)AbortPolicy
     2.无声地放弃当前任务。DiscardPolicy
     3.丢弃队列最靠前的任务。DiscardOldestPolicy
     4.用调用者所在的线程来执行任务(除非线程池关闭)CallerRunsPolicy
     */
    private final static ExecutorService POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_IMUM_POOL_SIZE
            ,KEEP_LIVE_TIME, TimeUnit.MINUTES, WORK_QUEUE, THREAD_FACTORY, HANDLER);

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       //开启异步,
        final AsyncContext asyncContext = req.startAsync();
        //监听异步任务
        asyncContext.addListener(new AsyncListener() {
            @Override
            public void onComplete(AsyncEvent asyncEvent) throws IOException {
                System.out.println("监听到异步任务完成了");
            }

            @Override
            public void onTimeout(AsyncEvent asyncEvent) throws IOException {

            }

            @Override
            public void onError(AsyncEvent asyncEvent) throws IOException {

            }

            @Override
            public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
                System.out.println("开始一个异步任务");
            }
        });

        final ServletInputStream input = req.getInputStream();
        //设置读监听
        input.setReadListener(new ReadListener() {
            /**
             * TCP端口缓存有数据时回调。
             * 当请求携带有参数的时候,会进入此方法,反之则不进入。
             * @throws IOException
             */
            @Override
            public void onDataAvailable() throws IOException {
                byte[] buff = new byte[1 * 1024];
                int readBytes = 0;
                while ( input.isReady() && !input.isFinished() ) {
                    readBytes += input.read(buff);
                }
                System.out.println("request参数大小:" + readBytes);
            }

            /**
             * onDataAvailable()结束之后运行:
             * 所有数据读取完
             * @throws IOException
             */
            @Override
            public void onAllDataRead() throws IOException {
                POOL_EXECUTOR.execute(()->{
                    try {
                        TimeUnit.SECONDS.sleep(3);
                        resp.setContentType("text/html");
                        resp.setCharacterEncoding("UTF-8");
                        PrintWriter printWriter = asyncContext.getResponse().getWriter();
                        printWriter.println("我是结果:" + new Date());
                    } catch (IOException e) {
                        e.printStackTrace();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        //异步任务完成通知
                        asyncContext.complete();
                        System.out.println("异步任务完成");
                    }
                });
            }

            @Override
            public void onError(Throwable throwable) {

            }
        });

        System.out.println("先释放容器线程,异步任务在执行...");

    }



    private static class TaskThreadFactory implements ThreadFactory {
        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(r);
            return t;
        }
    }

}

参考《Java异步编程实战》翟陆续

猜你喜欢

转载自blog.csdn.net/qq_38974073/article/details/109129258