程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> JSP編程 >> 關於JSP >> Servlet及JSP中的多線程同步問題

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

編輯:關於JSP

  Servlet/jsp(SUN企業級應用的首選)技術和ASP、PHP等相比,由於其多線程運行而具有很高的執行效率。由於Servlet/jsp(SUN企業級應用的首選)默認是以多線程模式執行的,所以,在編寫代碼時需要非常細致地考慮多線程的同步問題。然而,很多人編寫Servlet/jsp(SUN企業級應用的首選)程序時並沒有注意到多線程同步的問題,這往往造成編寫的程序在少量用戶訪問時沒有任何問題,而在並發用戶上升到一定值時,就會經常出現一些莫明其妙的問題,對於這類隨機性的問題調試難度也很大。

  一、在Servlet/jsp(SUN企業級應用的首選)中的幾種變量類型

  在編寫Servlet/jsp(SUN企業級應用的首選)程序時,對實例變量一定要小心使用。因為實例變量是非線程安全的。在Servlet/jsp(SUN企業級應用的首選)中,變量可以歸為下面的幾類:

  1. 類變量

  request,response,session,config,application,以及jsp(SUN企業級應用的首選)頁面內置的page, pageContext。其中除了application外,其它都是線程安全的。

  2. 實例變量

  實例變量是實例所有的,在堆中分配。在Servlet/jsp(SUN企業級應用的首選)容器中,一般僅實例化一個Servlet/jsp(SUN企業級應用的首選)實例,啟動多個該實例的線程來處理請求。而實例變量是該實例所有的線程所共享,所以,實例變量不是線程安全的。

  3. 局部變量

  局部變量在堆棧中分配,因為每一個線程有自己的執行堆棧,所以,局部變量是線程安全的。

  二、在Servlet/jsp(SUN企業級應用的首選)中的多線程同步問題

  在jsp(SUN企業級應用的首選)中,使用實例變量要特別謹慎。首先請看下面的代碼:

// instanceconcurrenttest.jsp(SUN企業級應用的首選)<%@ page contentType="text/html;charset=GBK" %><%!     //定義實例變量     String username;     String password;    java.io.PrintWriter output;%><%     //從request中獲取參數    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>");     } %>


  在這個頁面中,首先定義了兩個實例變量,username和password。然後在從request中獲取這兩個參數,並調用showUserInfo()方法將請求用戶的信息回顯在該客戶的浏覽器上。在一個用戶訪問是,不存在問題。但在多個用戶並發訪問時,就會出現其它用戶的信息顯示在另外一些用戶的浏覽器上的問題。這是一個嚴重的問題。為了突出並發問題,便於測試、觀察,我們在回顯用戶信息時執行了一個模擬的費時操作,比如,下面的兩個用戶同時訪問(可以啟動兩個IE浏覽器,或者在兩台機器上同時訪問):

a: http://localhost:8080/instanceconcurrenttest.jsp(SUN企業級應用的首選)?username=a&password=123

b: http://localhost:8080/instanceconcurrenttest.jsp(SUN企業級應用的首選)?username=b&password=456

如果a點擊鏈接後,b再點擊鏈接,那麼,a將返回一個空白屏幕,b則得到a以及b兩個線程的輸出。請看下面的屏幕截圖:



圖1:a的屏幕




圖2:b的屏幕


  從運行結果的截圖上可以看到,Web服務器啟動了兩個線程分別來處理來自a和b的請求,但是在a卻得到一個空白的屏幕。這是因為上面程序中的output, username和password都是實例變量,是所有線程共享的。在a訪問該頁面後,將output設置為a的輸出,username,password分別置為a的信息,而在a執行printUserInfo()輸出username和password信息前,b又訪問了該頁面,把username和password置為了b的信息,並把輸出output指向到了b。隨後a的線程打印時,就打印到了b的屏幕了,並且,a的用戶名和密碼也被b的取代。請參加下圖所示:

9 7 3 123 4 8 :

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved