天天看點

Servlet及JSP中的多線程同步問題

Servlet/JSP鎶€鏈拰ASP銆丳HP绛夌浉姣旓紝鐢變簬鍏跺绾跨▼杩愯鑰屽叿鏈夊緢楂樼殑鎵ц鏁堢巼銆傜敱浜嶴ervlet/JSP榛樿鏄互澶氱嚎绋嬫ā寮忔墽琛岀殑锛屾墍浠ワ紝鍦ㄧ紪鍐欎唬鐮佹椂闇€瑕侀潪甯哥粏鑷村湴鑰冭檻澶氱嚎绋嬬殑鍚屾闂銆傜劧鑰岋紝寰堝浜虹紪鍐橲ervlet/JSP绋嬪簭鏃跺苟娌℃湁娉ㄦ剰鍒闆绾跨▼鍚屾鐨勯棶棰橈紝杩欏線寰€閫犳垚缂栧啓鐨勭▼搴忓湪灏戦噺鐢ㄦ埛璁塊棶鏃舵病鏈変換浣曢棶棰橈紝鑰屽湪骞跺彂鐢ㄦ埛涓婂崌鍒頒竴瀹氬€兼椂锛屽氨浼氱粡甯稿嚭鐜頒竴浜涜帿鏄庡叾濡欑殑闂锛屽浜庤繖绫婚殢鏈烘€х殑闂璋冭瘯闅懼害涔熷緢澶с€?

銆€銆€

涓€銆佸湪Servlet/JSP涓殑鍑犵鍙橀噺绫誨瀷

銆€銆€鍦ㄧ紪鍐橲ervlet/JSP绋嬪簭鏃訛紝瀵瑰疄渚嬪彉閲忎竴瀹氳灏忓績浣跨敤銆傚洜涓哄疄渚嬪彉閲忔槸闈炵嚎绋嬪畨鍏ㄧ殑銆傚湪Servlet/JSP涓紝鍙橀噺鍙互褰掍負涓嬮潰鐨勫嚑绫夥細

銆€銆€

1. 绫誨彉閲?/b>

銆€銆€request锛宺esponse锛宻ession锛宑onfig锛宎pplication锛屼互鍙奐SP椤甸潰鍐呯疆鐨刾age, pageContext銆傚叾涓櫎浜哸pplication澶栵紝鍏跺畠閮芥槸绾跨▼瀹夊叏鐨勩€?

銆€銆€

2. 瀹炰緥鍙橀噺

銆€銆€瀹炰緥鍙橀噺鏄疄渚嬫墍鏈夌殑锛屽湪鍫嗕腑鍒嗛厤銆傚湪Servlet/JSP瀹瑰櫒涓紝涓€鑸粎瀹炰緥鍖栦竴涓猄ervlet/JSP瀹炰緥锛屽惎鍔ㄥ涓瀹炰緥鐨勭嚎绋嬫潵澶勭悊璇鋒眰銆傝€屽疄渚嬪彉閲忔槸璇ュ疄渚嬫墍鏈夌殑绾跨▼鎵€鍏變韓锛屾墍浠ワ紝瀹炰緥鍙橀噺涓嶆槸绾跨▼瀹夊叏鐨勩€?

銆€銆€

3. 灞€閮ㄥ彉閲?/b>

銆€銆€灞€閮ㄥ彉閲忓湪鍫嗘爤涓垎閰嶏紝鍥犱負姣忎竴涓嚎绋嬫湁鑷繁鐨勬墽琛屽爢鏍堬紝鎵€浠ワ紝灞€閮ㄥ彉閲忔槸绾跨▼瀹夊叏鐨勩€?

銆€銆€

浜屻€佸湪Servlet/JSP涓殑澶氱嚎绋嬪悓姝ラ棶棰?/b>

銆€銆€鍦↗SP涓紝浣跨敤瀹炰緥鍙橀噺瑕佺壒鍒皚鎱庛€傞鍏堣鐪嬩笅闈㈢殑浠g爜锛?

// instanceconcurrenttest.jsp
<%@ page contentType="text/html;charset=GBK" %>
<%! 
    //瀹氫箟瀹炰緥鍙橀噺 
    String username; 
    String password;
    java.io.PrintWriter output;
%>
<% 
    //浠巖equest涓幏鍙栧弬鏁?    username = request.getParameter("username");
    password = request.getParameter("password");
    output = response.getWriter();
    showUserInfo(); 
 %>
 <%! 
    public void showUserInfo() {  
       //涓轟簡绐佸嚭骞跺彂闂锛屽湪杩欏効棣栧厛鎵ц涓€涓垂鏃舵搷浣? 
       int i =0;  
       double sum = 0.0;  
       while (i++ < 200000000) {
             sum += i;  
       }    
       
       output.println(Thread.currentThread().getName() + "<br>");
       output.println("username:" + username + "<br>"); 
       output.println("password:" + password + "<br>"); 
    }
 %>
            

銆€銆€鍦ㄨ繖涓〉闈腑锛岄鍏堝畾涔変簡涓や釜瀹炰緥鍙橀噺锛寀sername鍜宲assword銆傜劧鍚庡湪浠巖equest涓幏鍙栬繖涓や釜鍙傛暟锛屽苟璋冪敤showUserInfo()鏂規硶灏嗚姹傜敤鎴風殑淇℃伅鍥炴樉鍦ㄨ瀹㈡埛鐨勬祻瑙堝櫒涓娿€傚湪涓€涓敤鎴瘋闂槸锛屼笉瀛樺湪闂銆備絾鍦ㄥ涓敤鎴峰苟鍙戣闂椂锛屽氨浼氬嚭鐜闆叾瀹冪敤鎴風殑淇℃伅鏄劇ず鍦ㄥ彟澶栦竴浜涚敤鎴風殑娴忚鍣ㄤ笂鐨勯棶棰樸€傝繖鏄竴涓弗閲嶇殑闂銆備負浜嗙獊鍑哄苟鍙戦棶棰橈紝渚誇簬娴嬭瘯銆佽瀵燂紝鎴戜滑鍦ㄥ洖鏄劇敤鎴蜂俊鎭椂鎵ц浜嗕竴涓ā鎷熺殑璐規椂鎿嶄綔锛屾瘮濡傦紝涓嬮潰鐨勪袱涓敤鎴峰悓鏃惰闂紙鍙互鍚姩涓や釜IE娴忚鍣紝鎴栬€呭湪涓ゅ彴鏈哄櫒涓婂悓鏃惰闂級锛?

a锛?http://localhost:8080/instanceconcurrenttest.jsp?username=a&password=123

b锛?http://localhost:8080/instanceconcurrenttest.jsp?username=b&password=456

濡傛灉a鐐瑰嚮閾炬帴鍚庯紝b鍐嶇偣鍑婚摼鎺ワ紝閭d箞锛宎灏嗚繑鍥炰竴涓┖鐧藉睆骞曪紝b鍒欏緱鍒癮浠ュ強b涓や釜绾跨▼鐨勮緭鍑恒€傝鐪嬩笅闈㈢殑灞忓箷鎴浘锛?

鍥?锛歛鐨勫睆骞?

鍥?锛歜鐨勫睆骞?

銆€銆€浠庤繍琛岀粨鏋滅殑鎴浘涓婂彲浠ョ湅鍒幫紝Web鏈嶅姟鍣ㄥ惎鍔ㄤ簡涓や釜绾跨▼鍒嗗埆鏉ュ鐞嗘潵鑷猘鍜宐鐨勮姹傦紝浣嗘槸鍦╝鍗村緱鍒頒竴涓┖鐧界殑灞忓箷銆傝繖鏄洜涓轟笂闈㈢▼搴忎腑鐨刼utput, username鍜宲assword閮芥槸瀹炰緥鍙橀噺锛屾槸鎵€鏈夌嚎绋嬪叡浜殑銆傚湪a璁塊棶璇ラ〉闈㈠悗锛屽皢output璁劇疆涓篴鐨勮緭鍑猴紝username,password鍒嗗埆缃負a鐨勪俊鎭紝鑰屽湪a鎵цprintUserInfo()杈撳嚭username鍜宲assword淇℃伅鍓嶏紝b鍙堣闂簡璇ラ〉闈紝鎶妘sername鍜宲assword缃負浜哹鐨勪俊鎭紝骞舵妸杈撳嚭output鎸囧悜鍒頒簡b銆傞殢鍚巃鐨勭嚎绋嬫墦鍗版椂锛屽氨鎵撳嵃鍒頒簡b鐨勫睆骞曚簡锛屽苟涓旓紝a鐨勭敤鎴峰悕鍜屽瘑鐮佷篃琚玝鐨勫彇浠c€傝鍙傚姞涓嬪浘鎵€绀猴細

鍥?锛歛銆乥涓や釜绾跨▼鐨勬椂闂寸嚎

銆€銆€鑰屽疄闄呯▼搴忎腑锛岀敱浜庤缃疄渚嬪彉閲忥紝浣跨敤瀹炰緥鍙橀噺杩欎袱涓椂闂寸偣闈炲父鎺ヨ繎锛屾墍浠ワ紝鍍忔湰渚嬬殑鍚屾闂骞舵病鏈夎繖涔堢獊鍑猴紝鍙兘浼氬伓灏斿嚭鐜幫紝浣嗚繖鍗存洿鍔犲叿鏈夊嵄闄╂€э紝涔熸洿鍔犻毦浜庤皟璇曘€?

銆€銆€鍚屾牱锛屽浜嶴ervlet涔熷瓨鍦ㄥ疄渚嬪彉閲忕殑澶氱嚎绋嬮棶棰橈紝璇風湅涓婇潰椤甸潰鐨凷ervlet鐗堬細

// InstanceConcurrentTest.java
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.PrintWriter;
public class InstanceConcurrentTest extends HttpServlet
 { 
      String username; 
      String password; 
      PrintWriter out; 
      public void doGet(HttpServletRequest request, 
       HttpServletResponse response)          
       throws ServletException,java.io.IOException 
       {  
           //浠巖equest涓幏鍙栧弬鏁? 
    username = request.getParameter("username");
    password = request.getParameter("password"); 
    System.out.println(Thread.currentThread().getName() +
     " | set username:" + username);
    out = response.getWriter(); 
    showUserInfo();  
       } 
       public void showUserInfo() {  
           //涓轟簡绐佸嚭骞跺彂闂锛屽湪杩欏効棣栧厛鎵ц涓€涓垂鏃舵搷浣? 
    int i =0;  
    double sum = 0.0;  
    while (i++ < 200000000) { 
      sum += i;  
    }  
    out.println("thread:" + Thread.currentThread().getName());
    out.println("username:"+ username); 
    out.println("password:" + password); 
 }
}
            
銆€銆€

涓夈€佽В鍐蟲柟妗?/b>

銆€銆€

1. 浠ュ崟绾跨▼杩愯Servlet/JSP

銆€銆€鍦↗SP涓紝閫氳繃璁劇疆锛?lt;%@ page isThreadSafe="false" %>锛屽湪Servlet涓紝閫氳繃瀹炵幇javax.servlet.SingleThreadModel锛屾鏃禬eb瀹瑰櫒灏嗕繚璇丣SP鎴朣ervlet瀹炰緥浠ュ崟绾跨▼鏂瑰紡杩愯銆?

銆€銆€閲嶈鎻愮ず锛氬湪娴嬭瘯涓彂鐜幫紝Tomcat 4.1.17涓嶈兘姝g‘鏀寔isThreadSafe灞炴€э紝鎵€浠ワ紝鎸囧畾isTheadSafe涓篺alse鍚庯紝鍦═omcat 4.1.17涓粛鐒跺嚭鐜闆绾跨▼闂锛岃繖鏄疶omcat 4.1.17鐨凚ug銆傚湪Tomcat 3.3.1鍜孯esin 2.1.5涓祴璇曢€氳繃銆?

銆€銆€

2. 鍘婚櫎瀹炰緥鍙橀噺锛岄€氳繃鍙傛暟浼犻€?/b>

銆€銆€浠庝笂闈㈢殑鍒嗘瀽鍙锛屽簲璇ュ湪Servlet/JSP涓敖閲忛伩鍏嶄嬌鐢ㄥ疄渚嬪彉閲忋€傛瘮濡傦紝涓嬮潰鐨勪慨姝d唬鐮侊紝鍘婚櫎浜嗗疄渚嬪彉閲忥紝閫氳繃瀹氫箟灞€閮ㄥ彉閲忥紝骞跺弬鏁拌繘琛屼紶閫掋€傝繖鏍鳳紝鐢變簬灞€閮ㄥ彉閲忔槸鍦ㄧ嚎绋嬬殑鍫嗘爤涓繘琛屽垎閰嶇殑锛屾墍浠ユ槸绾跨▼瀹夊叏鐨勩€備笉浼氬嚭鐜闆绾跨▼鍚屾鐨勯棶棰樸€備唬鐮佸涓嬶細

<%@ page contentType="text/html;charset=GBK" %>
<% 
    //浣跨敤灞€閮ㄥ彉閲?    String username;
    String password;
    java.io.PrintWriter output;
    //浠巖equest涓幏鍙栧弬鏁?    username = request.getParameter("username");
    password = request.getParameter("password");
    output = response.getWriter();
    showUserInfo(output, username, password);
%>
<%! 
    public void showUserInfo(java.io.PrintWriter _output,
     String _username, String _password) {
    //涓轟簡绐佸嚭骞跺彂闂锛屽湪杩欏効棣栧厛鎵ц涓€涓垂鏃舵搷浣?      int i =0; 
      double sum = 0.0; 
      while (i++ < 200000000) { 
        sum += i;  
      }    
      _output.println(Thread.currentThread().getName() + "<br>");
      _output.println("username:" + _username + "<br>");
      _output.println("password:" + _password + "<br>");
      }
%>
            
娉細鏈夌殑璧勬枡涓婃寚鍑哄湪printUserInfo()鏂規硶鎴栬€呭疄渚嬪彉閲忕殑鐩稿叧鎿嶄綔璇彞涓婁嬌鐢╯ynchronized鍏抽敭瀛楄繘琛屽悓姝ワ紝浣嗚繖鏍峰苟涓嶈兘瑙e喅澶氱嚎绋嬬殑闂銆傚洜涓猴紝杩欐牱铏界劧鍙互浣垮瀹炰緥鍙橀噺鐨勬搷浣滀唬鐮佽繘琛屽悓姝ワ紝浣嗗苟涓嶈兘闃繪涓€涓嚎绋嬩嬌鐢ㄥ彟澶栦竴涓嚎绋嬩慨鏀瑰悗鐨勨€滆剰鐨勨€濆疄渚嬪彉閲忋€傛墍浠ワ紝闄や簡闄嶄綆杩愯鏁堢巼澶栵紝涓嶄細璧峰埌棰勬湡鏁堟灉銆?