如何用Synchronied解決Servlet多線程安全問題

用Synchronied解決多線程安全問題:
馬克- to-win:馬克 java社區(qū):防盜版實名手機(jī)尾號: 73203。
馬克-to-win:我們先鋪墊Servlet的多線程基礎(chǔ)知識。到現(xiàn)在為止,我們所接觸到的Servlet都是這樣的:第一個人訪問Servlet的時候,Servlet會被實例化。之后的人再訪問這個Servlet的時候,這個Servlet就不再被實例化了,而是采取線程的模式。用每一個由這個 servlet而來的線程來應(yīng)答來請求的客戶。這樣的話,Servlet的實例變量,實際上是被所有客戶的線程共享的。這樣就會出現(xiàn)線程安全的問題。一談到多線程安全,就需要談到我"Java初級"部分第六章的那個多線程安全的例子。這里基本還是用那個例子,只不過是放在Servlet環(huán)境下。那里對 Critical data(關(guān)鍵數(shù)據(jù)[多個線程同時會修改的數(shù)據(jù)])的解決方案,就是在訪問Critical data的方法前面加上關(guān)鍵字Synchronized。這里建議的解決方案也是這樣。馬克-to-win:我們先看一個沒有加Synchonized的 critical data的例子。見下面例:2.1.1,還是像"Java初級"部分第六章那里一樣,onlySellOne對于一個人來講,一次只能賣一本書。對于本例來講,我們用一個瀏覽器模擬一個人。觀察瀏覽器,我們發(fā)現(xiàn),對于有的人(http-8080-Processor25)來講,開始還是18本書,買了一本書之后(調(diào)用一次onlySellOne),自己一看,還剩下16本書。這里顯然出現(xiàn)了問題。問題就在于,有其他人同時也在買書。關(guān)鍵數(shù)據(jù)(bookNum)可以被多個線程同時修改。對于例:2.1.2,我們通過在onlySellOne方法前面加上Synchronized關(guān)鍵字,使得這個方法,在被任何線程調(diào)用時,其他線程就不能再調(diào)用,而只能排隊等候。這樣,結(jié)果就完美了。即使兩個瀏覽器是同時運行的,數(shù)據(jù)也是一個一個減下來的。






例:2.1.1


ServletHello1.java:

package com;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class ServletHello1 extends HttpServlet {
    int bookNum=20;
    protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        PrintWriter pw = response.getWriter();
        while (bookNum>0){
            onlySellOne(pw);
        }
    }
    void onlySellOne(PrintWriter pw) throws IOException {
        if (bookNum > 0) {
            pw.println(Thread.currentThread().getName()
                    + " before" + bookNum);
            pw.flush();
            bookNum--;
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
            }
            pw.println(Thread.currentThread().getName()
                    + " after " + bookNum);
            pw.flush();
        }
    }
}
































例:2.1.2

package com;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class ServletHello1 extends HttpServlet {
    int bookNum=20;
    protected void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
        PrintWriter pw = response.getWriter();
        while (bookNum>0) {
            onlySellOne(pw);
        }
    }
    synchronized void onlySellOne(PrintWriter pw) throws IOException {
        if (bookNum > 0) {
            pw.println(Thread.currentThread().getName()
                    + " before" + bookNum);
            pw.flush();
            bookNum--;
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
            }
            pw.println(Thread.currentThread().getName()
                    + " after " + bookNum);
            pw.flush();
        }
    }
}