Servlet是否适合复合操作?

时间:2015-04-26 21:31:32

标签: java servlets thread-safety

Servlet是非线程安全的,在不同请求的方法调用之间状态可能会丢失。

但是我可以在单个请求期间安全地在自己的Servlet方法之间保持状态以实现复合操作吗?

像这样:

public class MyServlet extends HttpServletRequest {

    private String var;

    void addH() {
        var += "h";
    }

    void addI() {
        var += "i";
    }

    void doGet(...) {
        addH();
        addI();
        // var = "hi"?
    }
}

即使是并发请求,var在这种情况下是否包含正确的值?换句话说,它是否像EJB中的无状态Bean一样工作?

2 个答案:

答案 0 :(得分:1)

public class MyServlet extends HttpServletRequest {

    private String var = "";

    void addH() {
        var += "h";
    }

    void addI(long dontAnswerBefore) {
        while(System.currentTimeMillis() < dontAnswerBefore) {
          // Do nothing 
        }
        var += "i";
    }

    void doGet(...) {
        long now = System.currentTimeMillis();
        addH();
        addI(now + 10_000);
        resp.write(var);
    }
}

这应该可以让您在两个标签或两个不同的浏览器中生成两个请求10秒钟。

答案 1 :(得分:1)

不,你不能。就像你说的,servlet不是线程安全的。没有受保护的空间&#34;请求存在。因此,多个线程(以及请求)可以同时命中var。如果你想要这样一个受保护的空间&#34;您需要同步doGet()(这当然会破坏并发)或执行类似于使用ThreadLocal的操作,以便每个线程(以及请求)都有自己的实例范围状态的单独副本。 / p>

如果您不希望状态在请求之外保留,您可以在doGet()内创建状态并将其传递给其他方法:

void doGet(...) {
    StringBuilder var = new StringBuilder();
    addH(var);
    addI(var);
    resp.write(var.toString());
}

void addH(StringBuilder var) {
    var.append('h');
}

void addI(StringBuilder var) {
    ver.append('i');
}