0

我有一个 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>");
    }



}
4

1 回答 1

4

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

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

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

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

因此,它不会从(例如)8 到 10,而是从 8 到 9,缺少一个增量。

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

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

于 2013-07-07T15:11:08.017 回答