如果我的Servlet实例变量是StringBuffer类型,它是否是线程安全的?

时间:2013-12-25 03:16:31

标签: java multithreading java-ee servlets thread-safety

我要澄清的第一件事是,我知道Servlet是单实例多线程模型。 Container维护在实例上,并为每个要处理的请求创建多个线程,并且所有线程在同一个servlet实例上工作。此外,我们不应该在servlet中维护状态,因为它会导致多线程/并发问题。凉!!如果状态(servlet的成员)本身是线程安全的呢?如下例所示

public class MyCrazyServlet extends HttpServlet {
  StringBuffer s1 = new StringBuffer("stackoverflow");
  static StringBuffer s2 = new StringBuffer("stackexchange");
  public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String s3 = "I'm safe";
    HttpSession crazySession = request.getSession();
    //more stuff here
  }
}

在上面的代码片段中,我假设除了crazySession局部变量(HttpSession实例)之外的所有其他内容(s1,s2和s3)都是线程安全的

如果我的理解错误,请更正

1 个答案:

答案 0 :(得分:3)

在给定的代码段中,s2永远不会被修改,因此它必须是安全的。但现在这不是真正有趣的用例,是吗?

StringBuffer是线程安全的,因为如果两个不同的线程同时修改它,一个调用将等待另一个调用结束,这样两个调用都将完全执行而不会互相混淆。

请考虑以下代码段:

// name is retrieved from the calling session
public void addName (String name) {
    // s2 is defined as:
    //    static StringBuffer s2 = new StringBuffer("stackexchange")
    // by the OP
    s2.append(name);
}

如果您(JavaHopper)和我(Mureinik)同时调用此函数,则可以保证内容不会被扰乱。 根据呼叫的确切时间和上下文切换,s2将包含"stackexchangeJavaHopperMureinik""stackexchangeMureinikJavaHopper"

但这是陷阱 - 你需要非常,非常小心你的电话。通常情况下,您需要链接多个呼叫,例如:

// name is retrieved from the calling session
public void addName (String name) {
    // s2 is defined as:
    //    static StringBuffer s2 = new StringBuffer("stackexchange")
    // by the OP
    s2.append("[").append(name).append("]");
}

在此示例中,每个append都是不同的呼叫。因此,上述两个并发调用可能会产生有效的结果,如"stackexchange[JavaHopper][Mureinik]",但可能会产生类似"stackexchange[JavaHopper[Mureinik]]"的内容。

总结一下:小心。要非常小心。根据代码的复杂程度,最好自己处理同步。