如何用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();
        }
    }
}