熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java高級技術 >> 正文

深入研究Servlet線程安全性問題

2013-11-23 19:41:40  來源: Java高級技術 

  Servlet/JSP技術和ASPPHP等相比由於其多線程運行而具有很高的執行效率由於Servlet/JSP默認是以多線程模式執行的所以在編寫代碼時需要非常細致地考慮多線程的安全性問題然而很多人編寫Servlet/JSP程序時並沒有注意到多線程安全性的問題這往往造成編寫的程序在少量用戶訪問時沒有任何問題而在並發用戶上升到一定值時就會經常出現一些莫明其妙的問題
  
  Servlet的多線程機制
  
  Servlet體系結構是建立在Java多線程機制之上的它的生命周期是由Web容器負責的當客戶端第一次請求某個Servlet時Servlet容器將會根據webxml配置文件實例化這個Servlet類當有新的客戶端請求該Servlet時一般不會再實例化該Servlet類也就是有多個線程在使用這個實例Servlet容器會自動使用線程池等技術來支持系統的運行如圖所示
  
 

  
Servlet線程池

  
  這樣當兩個或多個線程同時訪問同一個Servlet時可能會發生多個線程同時訪問同一資源的情況數據可能會變得不一致所以在用Servlet構建的Web應用時如果不注意線程安全的問題會使所寫的Servlet程序有難以發現的錯誤
  
  Servlet的線程安全問題
  
  Servlet的線程安全問題主要是由於實例變量使用不當而引起的這裡以一個現實的例子來說明
  
  Import javaxservlet *;
  Import javaxservlethttp *;
  Import javaio *;
  Public class Concurrent Test extends HttpServlet {PrintWriter output;
  Public void service (HttpServletRequest request
  HttpServletResponse response) throws ServletException IOException {String username;
  ResponsesetContentType (text/html; charset=gb);
  Username = requestgetParameter (username);
  Output = responsegetWriter ();
  Try {Thread sleep (); //為了突出並發問題在這設置一個延時
  } Catch (Interrupted Exception e){}
  outputprintln(用戶名:+Username+<BR>);
  }
  }
  
  該Servlet中定義了一個實例變量output在service方法將其賦值為用戶的輸出當一個用戶訪問該Servlet時程序會正常的運行但當多個用戶並發訪問時就可能會出現其它用戶的信息顯示在另外一些用戶的浏覽器上的問題這是一個嚴重的問題為了突出並發問題便於測試觀察我們在回顯用戶信息時執行了一個延時的操作假設已在webxml配置文件中注冊了該Servlet現有兩個用戶a和b同時訪問該Servlet(可以啟動兩個IE浏覽器或者在兩台機器上同時訪問)即同時在浏覽器中輸入
  
  a//localhost: /servlet/ConcurrentTest? Username=a
  
  b//localhost: /servlet/ConcurrentTest? Username=b
  
  如果用戶b比用戶a回車的時間稍慢一點將得到如圖所示的輸出
  
 educitycn/img_///jpg>

  
a用戶和b用戶的浏覽器輸出

  
  從圖中可以看到Web服務器啟動了兩個線程分別處理來自用戶a和用戶b的請求但是在用戶a的浏覽器上卻得到一個空白的屏幕用戶a的信息顯示在用戶b的浏覽器上該Servlet存在線程不安全問題下面我們就從分析該實例的內存模型入手觀察不同時刻實例變量output的值來分析使該Servlet線程不安全的原因
  
  Java的內存模型JMM(Java Memory Model)JMM主要是為了規定了線程和內存之間的一些關系根據JMM的設計系統存在一個主內存(Main Memory)Java中所有實例變量都儲存在主存中對於所有線程都是共享的每條線程都有自己的工作內存(Working Memory)工作內存由緩存和堆棧兩部分組成緩存中保存的是主存中變量的拷貝緩存可能並不總和主存同步也就是緩存中變量的修改可能沒有立刻寫到主存中堆棧中保存的是線程的局部變量線程之間無法相互直接訪問堆棧中的變量根據JMM我們可以將論文中所討論的Servlet實例的內存模型抽象為圖所示的模型
  
 educitycn/img_///jpg>

  
Servlet實例的JMM模型

  
  下面根據圖所示的內存模型來分析當用戶a和b的線程(簡稱為a線程b線程)並發執行時Servlet實例中所涉及變量的變化情況及線程的執行情況如圖所示
  
educitycn/img_///gif>

  
Servlet實例的線程調度情況

  
  從圖中可以清楚的看到由於b線程對實例變量output的修改覆蓋了a線程對實例變量output的修改從而導致了用戶a的信息顯示在了用戶b的浏覽器上如果在a線程執行輸出語句時b線程對output的修改還沒有刷新到主存那麼將不會出現圖所示的輸出結果因此這只是一種偶然現象但這更增加了程序潛在的危險性
From:http://tw.wingwit.com/Article/program/Java/gj/201311/27302.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.