<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    聶永的博客

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

    Servlet 3.0筆記之Servlet單實例以及線程安全小結

    眾所周知,Servlet為單實例多線程,非線程安全的。

    若一個Servlet對應多個URL映射,那么將會生成一個還是多個Servlet實例呢?

    最好的辦法就是動手體驗一下

    @WebServlet({ "/demoServlet1", "/demoServlet2" })
    public class DemoServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request,
    HttpServletResponse response) throws ServletException, IOException {
    PrintWriter out = response.getWriter();
    out.println(request.getServletPath() + "[" + this + "]");
    out.flush();
    out.close();
    }
    }

    輸出結果:

    /demoServlet1[com.learn.servlet3.thread.DemoServlet@1320a41]
    /demoServlet2[com.learn.servlet3.thread.DemoServlet@9abce9]

    輸出結果可以看到映射/demoServlet1/demoServlet2對應Servlet實例是不同的。

    結果證明:Servlet將為每一個URL映射生成一個實例;一個Servlet可能存在多個示例,但每一個實例都會對應不同的URL映射。


    下面討論單個Servlet、多線程情況下保證數據線程同步的幾個方法。

    1. synchronized:代碼塊,方法
      大家都會使用的方式,不用詳細介紹了。
      建議優先選擇修飾方法。
    2. volatile
      輕量級的鎖,可以保證多線程情況單線程讀取所修飾變量時將會強制從共享內存中讀取最新值,但賦值操作并非原子性。
      一個具有簡單計數功能Servlet示范:
      /**
      * 使用Volatile作為輕量級鎖作為計數器
      *
      * @author yongboy
      * @date 2011-3-12
      * @version 1.0
      */
      @WebServlet("/volatileCountDemo")
      public class VolatileCountServlet extends HttpServlet {
      private static final long serialVersionUID = 1L;

      private volatile int num = 0;

      protected void doGet(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {
      addOne();
      response.getWriter().write("now access num : " + getNum());
      }

      /**
      * 讀取開銷低
      */
      private int getNum() {
      return num;
      }

      /**
      * 其寫入為非線程安全的,賦值操作開銷高
      */
      private synchronized void addOne() {
      num ++;
      }
      }
      我們在為volatile修飾屬性賦值時,還是加把鎖的。
    3. ThreadLocal
      可以保證每一個線程都可以獨享一份變量副本,每個線程可以獨立改變副本,不會影響到其它線程。
      這里假設多線程環境一個可能落顯無聊的示范,初始化一個計數,然后循環輸出:
      @WebServlet("/threadLocalServlet")
      public class ThreadLocalServlet extends HttpServlet {
      private static final long serialVersionUID = 1L;

      private static ThreadLocal threadLocal = new ThreadLocal() {
      @Override
      protected Integer initialValue() {
      return 0;
      }
      };

      protected void doGet(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {
      response.setHeader("Connection", "Keep-Alive");

      PrintWriter out = response.getWriter();
      out.println("start... " + " [" + Thread.currentThread() + "]");
      out.flush();

      for (int i = 0; i < 20; i++) {
      out.println(threadLocal.get());
      out.flush();

      threadLocal.set(threadLocal.get() + 1);
      }

      // 手動清理,當然隨著當前線程結束,亦會自動清理調
      threadLocal.remove();
      out.println("finish... ");
      out.flush();
      out.close();
      }
      }
      若創建一個對象較為昂貴,但又是非線程安全的,在某種情況下要求僅僅需要在線程中獨立變化,不會影響到其它線程。選擇使用ThreadLocal較好一些,嗯,還有,其內部使用到了WeakHashMap,弱引用,當前線程結束,意味著創建的對象副本也會被垃圾回收。
      Hibernate使用ThreadLocal創建Session;Spring亦用于創建對象會使用到一點。
      嗯,請注意這不是解決多線程共享變量的鑰匙,甚至你想讓某個屬性或對象在所有線程中都保持原子性,顯然這不是解決方案。
    4. Lock
      沒什么好說的,現在JDK版本支持顯式的加鎖,相比synchronized,添加與釋放更加靈活,功能更為全面。
      @WebServlet("/lockServlet")
      public class LockServlet extends HttpServlet {
      private static final long serialVersionUID = 1L;

      private static int num = 0;
      private static final Lock lock = new ReentrantLock();

      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      try{
      lock.lock();
      num ++;
      response.getWriter().println(num);
      }finally{
      lock.unlock();
      }
      }
      }
      必須手動釋放鎖,否則將會一直鎖定。
    5. wait/notify
      較老的線程線程同步方案,較之Lock,不建議再次使用。
    6. 原子操作
      原子包裝類,包括一些基本類型(int, long, double, boolean等)的包裝,對象屬性的包裝等。
      @WebServlet("/atomicServlet")
      public class AtomicServlet extends HttpServlet {
      private static final long serialVersionUID = 1L;
      private static final AtomicInteger num = new AtomicInteger(0);

      protected void doGet(HttpServletRequest request,
      HttpServletResponse response) throws ServletException, IOException {
      PrintWriter out = response.getWriter();
      out.println(num.incrementAndGet());
      out.flush();
      out.close();
      }
      }
      包裝類提供了很多的快捷方法,比如上面的incrementAndGet方法,自身增加1,然后返回結果值,并且還是線程安全的,省缺了我們很多手動、笨拙的編碼實現。
      更多原子類,請參見 java.util.concurrent.atomic包。
    7. 一些建議
      盡量不要在Servlet中單獨啟用線程
      使用盡可能使用局部變量
      盡可能避免使用鎖
    8. 數據結構小結
      在平常環境下使用的一些數據結構,在多線程并發環境下可選擇使用java.util.concurrent里內置替代品。下面有一個小結,僅供參考。
    非線程安全工具版JUC版本
    HashMap Collections.synchronizedMap ConcurrentHashMap
    ArrayList Collections.synchronizedList CopyOnWriteArrayList
    HashSet Collections.synchronizedSet synchronizedSet
    Queue   ConcurrentLinkedQueue



    Servlet線程安全有很太多的話題要說,以上僅僅為蜻蜓點水,真正需要學習和實踐的還有一段長路要學習。另,話說,這里已和Servlet版本無關,是知識積累和分享。

    posted on 2011-03-14 13:17 nieyong 閱讀(6437) 評論(4)  編輯  收藏 所屬分類: Servlet3

    評論

    # re: Servlet 3.0筆記之Servlet單實例以及線程安全小結[未登錄] 2011-03-15 09:18 Jarod

    眾所周知servlet是線程安全的,線程不安全的是你自己的狀態數據,與servlet完全無關  回復  更多評論   

    # re: Servlet 3.0筆記之Servlet單實例以及線程安全小結 2012-03-01 19:58 1111

    AnnotationServlet.doGet,Servlet: /AnnotationServlet servlet3.AnnotationServlet@5acb5e96
    AnnotationServlet.doGet,Servlet: /annotationServlet servlet3.AnnotationServlet@5acb5e96

    我的測試是不同URL,是同一個Servlet處理的哦..

    @WebServlet(urlPatterns ={"/annotationServlet","/AnnotationServlet"})
    public class AnnotationServlet extends HttpServlet
    {
    ...
    }  回復  更多評論   

    # re: Servlet 3.0筆記之Servlet單實例以及線程安全小結 2013-01-06 22:12 zelin

    /printServlet1[com.huawei.servlet.PrintServlet@136c1da]
    /printServlet1[com.huawei.servlet.PrintServlet@136c1da]
    朋友,我的輸出結果和你的不同啊。
    我的測試是不用URL,創建同一個Servlet。  回復  更多評論   

    # re: Servlet 3.0筆記之Servlet單實例以及線程安全小結 2015-08-20 10:17 浩哥

    應該是單實例!樓主能不能將環境配置搞出來  回復  更多評論   

    公告

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

    新浪微博,歡迎關注:

    導航

    <2011年3月>
    272812345
    6789101112
    13141516171819
    20212223242526
    272829303112
    3456789

    統計

    常用鏈接

    留言簿(58)

    隨筆分類(130)

    隨筆檔案(151)

    個人收藏

    最新隨筆

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 99视频在线免费看| 99爱在线观看免费完整版| 午夜成年女人毛片免费观看| 亚洲天堂一区在线| 免费看污成人午夜网站| 亚洲欧洲国产精品久久| 日本免费人成在线网站| 亚洲欧洲国产视频| 无码视频免费一区二三区 | 久久精品一区二区免费看| 亚洲乳大丰满中文字幕| 亚洲免费观看视频| 久久久亚洲欧洲日产国码二区| 久久国产乱子免费精品| 亚洲毛片无码专区亚洲乱| 97免费人妻无码视频| 亚洲人成欧美中文字幕| 又粗又硬又黄又爽的免费视频 | 视频免费在线观看| 亚洲网址在线观看你懂的| 免费黄色网址网站| 亚洲AV无码专区亚洲AV桃| 亚洲精品乱码久久久久久不卡 | 国产成人精品日本亚洲网址| 香蕉高清免费永久在线视频| 三年片在线观看免费观看大全中国| 国产亚洲情侣一区二区无| 久久成人免费播放网站| 亚洲国产美女在线观看| 国产成人无码免费视频97| 97人妻精品全国免费视频| 亚洲伊人久久大香线蕉在观| 免费看国产一级片| 久久成人免费大片| 婷婷国产偷v国产偷v亚洲| 国产亚洲一区二区手机在线观看| 亚欧色视频在线观看免费| 特级毛片A级毛片100免费播放| 婷婷亚洲久悠悠色悠在线播放| 成人毛片免费在线观看| a级日本高清免费看|