Servlet中的澄清

时间:2013-07-07 14:46:59

标签: java-ee servlets

我有一个servlet代码,用于维护访问它的次数。

在doGet方法的某一点上,在访问该部分的次数上进行增量的点。

任何人都可以详细说明为什么要这样做以及如果在doGet方法中没有完成同步会产生什么影响。

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;

public class FirstAccessed extends HttpServlet{

    private Date first;
    private int count;

    public void init() throws ServletException {

        // Enter the time/date when the server calls this servlet and
        // initialize counter
    first = new Date();
        count = 0;
        return;

    }

    public void doGet(HttpServletRequest req, HttpServletResponse res)
                               throws ServletException, IOException {
        res.setContentType("text/plain");
        PrintWriter out = res.getWriter();
    int local_count;
    synchronized(this) {
        local_count = ++count;
    }
        out.println("<HTML>");
        out.println("<HEAD><TITLE>First Accessed Servlet</TITLE></HEAD>");
        out.println("<BODY>");
    out.println("This servlet was first loaded by the server at " + first);
    out.println("<br>The current time is " + new Date());
    out.println("<br>");
    out.println("This servlet has been accessed " + local_count + " times.");
        out.println("</BODY></HTML>");
    }



}

1 个答案:

答案 0 :(得分:4)

++不是原子操作。它涉及

  • 读取count
  • 的当前值
  • 递增它,
  • 并将新值重新分配给count

如果此块未同步,则并行执行doGet()方法的两个线程可能会进入竞争状态。例如,两个线程可能

  • 并行读取当前值(例如,读取8),
  • 然后递增值并并行重新分配新值。

而不是从(例如)8到10,它将从8变为9,缺少一个增量。

同步也是必要的,以确保一个线程所做的count的更改对之后读取其值的所有其他线程可见。如果没有同步,您也会有丢失增量的风险。

请注意,虽然您不在代码中的任何位置创建和执行线程,但Web容器本身会创建并执行它们。因此,如果您的应用的两个用户同时点击同一个链接,他们各自的请求将由两个不同的线程处理,两个线程同时调用您的servlet的doGet()方法。