聶永的博客

          記錄工作/學習的點點滴滴。

          Servlet 3.0筆記之Servlet的異步特性支持失效怎么辦?

          滿心歡喜的為Servlet 添加上異步支持注解(asyncSupported = true),不曾想,其異步特性完全不起作用,仔細檢測項目,發現存在一個編碼攔截器(Filter),雖使用注解,但未標明支持異步,導致被攔截的標注為異步支持的Servlet,異步特性皆失效。怎么辦,在Filter中注解里面添加asyncSupported = true。問題解決。
          但轉念一想,因歷史原因,遺留系統會存在很多的Servlet 2.*規范的Filter,無法支持異步,怎么辦?全部手動修改為注解版本,可能不太現實。還好,Doug Lea的JUC并發包,為我們提供了一種實現思路。
          實際步驟:
          1. 準備一個線程池
          2. 把當前請求相關屬性包裝進一個任務線程中
          3. 獲取當前任務線程執行結果(不一定會有返回值)
          4. 阻塞,執行完畢或超時,或被中斷異常,可以輸出客戶端
          5. 整個請求結束
          實際上,提交到一個線程池的任務線程,默認會返回一個Future對象,利用Future對象的get方法阻塞的特性,當前請求需要等待任務線程執行的結束,若指定時間內任務線程順利完成,則不必等到設定的時間的邊界即可自然往下執行。
          實際代碼:
          package com.servlet3.demo;
          import java.io.IOException;
          import java.io.PrintWriter;
          import java.util.concurrent.ExecutionException;
          import java.util.concurrent.ExecutorService;
          import java.util.concurrent.Executors;
          import java.util.concurrent.Future;
          import java.util.concurrent.ThreadFactory;
          import java.util.concurrent.ThreadPoolExecutor;
          import java.util.concurrent.TimeUnit;
          import java.util.concurrent.TimeoutException;
          import javax.servlet.ServletException;
          import javax.servlet.annotation.WebServlet;
          import javax.servlet.http.HttpServlet;
          import javax.servlet.http.HttpServletRequest;
          import javax.servlet.http.HttpServletResponse;
          /**
          * Servlet中添加异步支持
          *
          * @author yongboy
          * @time 2012-1-17
          * @version 1.0
          */
          @WebServlet(urlPatterns = "/async3")
          public class DemoAsync3Action extends HttpServlet {
          private static final long serialVersionUID = 1L;
          private final ExecutorService executor;
          {
          executor = Executors.newCachedThreadPool(new ThreadFactory() {
          public Thread newThread(Runnable r) {
          Thread thread = new Thread(r);
          thread.setName("DemoAsyncAction3 executor Thread "
          + thread.getId());
          thread.setPriority(Thread.MAX_PRIORITY);
          return thread;
          }
          });
          if (executor instanceof ThreadPoolExecutor) {
          // 不超过服务器CPU数目个线程较佳
          ((ThreadPoolExecutor) executor).setMaximumPoolSize(Runtime
          .getRuntime().availableProcessors());
          }
          }
          protected void doGet(HttpServletRequest request,
          HttpServletResponse response) throws ServletException, IOException {
          // 添加此属性,告诉浏览器,需要分段显示
          response.setHeader("Connection", "Keep-Alive");
          response.setContentType("text/html;charset=UTF-8");
          final PrintWriter out = response.getWriter();
          output(out, "the manual async start ...");
          Future<?> future = executor.submit(new Runnable() {
          @Override
          public void run() {
          try {
          // 假设实际业务耗时10秒
          Thread.sleep(10000L);
          } catch (InterruptedException e) {
          e.printStackTrace();
          }
          try {
          output(out, "the manual async goes here ...");
          } catch (IOException e) {
          e.printStackTrace();
          }
          }
          });
          boolean result = false;
          try {
          // 在此处,会阻塞当前线程,直到超时或线程执行完毕...
          future.get(10L, TimeUnit.SECONDS);
          result = true;
          } catch (InterruptedException e) {
          e.printStackTrace();
          } catch (ExecutionException e) {
          e.printStackTrace();
          } catch (TimeoutException e) {
          e.printStackTrace();
          } finally {
          future.cancel(true);
          }
          if (result) {
          output(out, "the manual async is ok ...");
          } else {
          output(out, "the manual async is failure ...");
          }
          // 按照顺序输出到此,结束请求
          output(out, "the end of manual async ...");
          out.close();
          }
          private static void output(PrintWriter out, String message)
          throws IOException {
          out.println(message);
          out.flush();
          }
          }

          需要備注說明的是,若Future.get()無參數,則意味著需要等待計算完成,然后獲取其結果。這樣可不用設定等待時間了。更多信息,請參考JDK。
          測試代碼下載

          posted on 2012-01-18 10:32 nieyong 閱讀(685) 評論(0)  編輯  收藏 所屬分類: Servlet3Java

          公告

          所有文章皆為原創,若轉載請標明出處,謝謝~

          新浪微博,歡迎關注:

          導航

          <2012年1月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          2930311234

          統計

          常用鏈接

          留言簿(58)

          隨筆分類(130)

          隨筆檔案(151)

          個人收藏

          最新隨筆

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 江山市| 临沧市| 商河县| 如皋市| 施甸县| 资兴市| 建宁县| 永春县| 北安市| 洪洞县| 唐海县| 贵州省| 惠东县| 峡江县| 抚顺县| 壤塘县| 寻乌县| 八宿县| 全南县| 晋宁县| 焦作市| 贞丰县| 山阴县| 海南省| 喜德县| 武穴市| 芷江| 滨海县| 莒南县| 宣威市| 南宫市| 临漳县| 高邮市| 东乌珠穆沁旗| 都昌县| 宿松县| 湾仔区| 安顺市| 天峨县| 桐乡市| 成安县|