对于前面AdderServlet案例,它的sum实例变量用来累计客户端请求进行加法运算的和。sum变量的初始为100,如果第一个客户请求加上100,那么sum变量变为200,接着第二个客户请求加上200,那么sum变量变400,HTTP请求和线程,以及HTTP请求和sum变量之间存在以下对应关系:

一个HTTP请求对应一个工作线程。

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

所有HTTP请求对应同一个sum变量。

由此可以推断出,所有的工作线程对应同一个sum变量,因此AdderServlet把sum变量定义为实例变量时合理的。当多个线程同时操作一个AdderServlet对象的sum实例变量时,如何避免并发问题呢?此时应该采用Java语言提供的同步机制。下面的示例AdderServlet2的service()方法把访问sum实例变量的代码块作为同步代码块来处理。

public class AdderServlet2 extends HttpServlet{

    private int sum = 100;

    public void service()throws ServletException,IOException{

         int increase = Integer.parseInt(request.getParameter("increase"));

         response.setContentType("text/html;charset=UTF-8");

         PrintWriter out = response.getWriter();

         synchronized(this){

              out.println(sum + "+" + increase + "=");

              try{

                   Thread.sleep(3000);

              }catch(Exception e){

                   e.printStackTrace();

              }

              sum+=increase;

              out.println(sum);

         }

         out.close();

    }

}

在web.xml文件中为AdderServlet2映射的URL为"/adder2",通过两个浏览器同时访问AdderServlet2,两个浏览器都会得到与当前请求匹配的响应结果。

Java同步机制确保在任意时刻,只允许有一个工作线程执行AdderServlet2对象的service()方法中的同步代码块。只有当这个工作线程退出同步代码块时,其他工作线程才允许执行同步代码块,这使得任意时刻不会有两个线程同时操纵同一个AdderServlet对象的sum实例变量,因此就能避免并发问题。

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄