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