【问题标题】:If my Servlet instance variable is of type StringBuffer, is it thread-safe? [duplicate]如果我的 Servlet 实例变量是 StringBuffer 类型,它是线程安全的吗? [复制]
【发布时间】:2014-01-13 03:48:00
【问题描述】:

首先我要澄清的是,我知道 Servlet 是单实例多线程模型。容器维护实例并为每个要处理的多个请求创建多个线程,并且所有线程都在同一个 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
  }
}

在上面的 sn-p 中,我假设除了 crazySession 局部变量(HttpSession 实例)之外,其他所有东西(s1、s2 和 s3)都是线程安全的

如果我的理解有误,请指正

【问题讨论】:

  • 是的,StringBuffer 是线程安全的。不要与非线程安全的非常相似的类 StringBuilder 混淆。
  • “一个线程安全的、可变的字符序列。” - docs.oracle.com/javase/7/docs/api/java/lang/StringBuffer.html
  • 那么,@DavidWallace 和 Nayuki...s1、s2 和 s3 都是线程安全的,对吧?我正在确认,因为我的导师说只有 s3 是线程安全的
  • StringBuffers 使用时会锁定,因此如果两个线程同时尝试访问它们,其中一个将不得不等待。
  • StringBuffer 保证对对象的多个并发调用一个一个完成,仅此而已。那么你的需求是什么?

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


【解决方案1】:

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

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

考虑以下代码sn-p:

// 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]]"这样的结果。

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

【讨论】:

    猜你喜欢
    • 2012-01-08
    • 2012-05-02
    • 2010-10-01
    • 2014-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多