如何用Synchronied解决Servlet多线程安全问题
用Synchronied解决多线程安全问题:
马克- to-win:马克 java社区:防盗版实名手机尾号: 73203。
马克-to-win:我们先铺垫Servlet的多线程基础知识。到现在为止,我们所接触到的Servlet都是这样的:第一个人访问Servlet的时候,Servlet会被实例化。之后的人再访问这个Servlet的时候,这个Servlet就不再被实例化了,而是采取线程的模式。用每一个由这个 servlet而来的线程来应答来请求的客户。这样的话,Servlet的实例变量,实际上是被所有客户的线程共享的。这样就会出现线程安全的问题。一谈到多线程安全,就需要谈到我"Java初级"部分第六章的那个多线程安全的例子。这里基本还是用那个例子,只不过是放在Servlet环境下。那里对 Critical data(关键数据[多个线程同时会修改的数据])的解决方案,就是在访问Critical data的方法前面加上关键字Synchronized。这里建议的解决方案也是这样。马克-to-win:我们先看一个没有加Synchonized的 critical data的例子。见下面例:2.1.1,还是像"Java初级"部分第六章那里一样,onlySellOne对于一个人来讲,一次只能卖一本书。对于本例来讲,我们用一个浏览器模拟一个人。观察浏览器,我们发现,对于有的人(http-8080-Processor25)来讲,开始还是18本书,买了一本书之后(调用一次onlySellOne),自己一看,还剩下16本书。这里显然出现了问题。问题就在于,有其他人同时也在买书。关键数据(bookNum)可以被多个线程同时修改。对于例:2.1.2,我们通过在onlySellOne方法前面加上Synchronized关键字,使得这个方法,在被任何线程调用时,其他线程就不能再调用,而只能排队等候。这样,结果就完美了。即使两个浏览器是同时运行的,数据也是一个一个减下来的。
例: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();
}
}
}