【问题标题】:Is that StringBuilder variable thread safe in this code?这段代码中的 StringBuilder 变量线程安全吗?
【发布时间】:2011-04-16 04:48:21
【问题描述】:

考虑下面的struts Action 类,我在execute 方法中使用了StringBuilder 变量。我的问题:变量sb 是否线程安全?

public DemoAction extends Action
{
    ......

    public ActionForward execute(.....)
    {
       StringBuilder sb = new StringBuilder();
    }
}

如果在execute() 之外声明相同的变量sb 会怎样。还记得 WebContainer 中只有一个 DemoAction 对象吗?

【问题讨论】:

标签: java stringbuilder thread-safety


【解决方案1】:

局部变量是线程安全的,只要没有其他线程以某种方式获得对同一字符串生成器实例的引用,它就是线程安全的。

【讨论】:

    【解决方案2】:

    来自the spec

    StringBuilder 的实例对于多线程使用是不安全的。如果需要这种同步,那么建议使用 StringBuffer。

    但是作为Konrad Rudolph pointed out,在你的情况下它是一个局部变量,所以你应该没问题

    【讨论】:

    • StringBuffer 或其他同步集合(如 Vector)几乎没有任何意义。如果我有两个线程试图访问我需要识别和同步关键部分的字符串缓冲区或列表,则很有可能。关键部分很可能需要包含多个方法调用。
    【解决方案3】:

    是的,局部变量本质上是线程安全的。每个线程都有自己的副本。

    【讨论】:

    • “只要你不传递引用”。谢谢,康拉德。
    【解决方案4】:

    它是线程安全的,因为您只在方法范围内创建和使用它,因此引用将存储在每个线程本地的堆栈空间中

    【讨论】:

      【解决方案5】:

      这是安全的。该变量是execute() 方法的局部变量,并且在每次调用此方法时都会创建,因此在多线程环境中,每个线程都可以拥有自己的sb 变量的单独副本。

      【讨论】:

        【解决方案6】:

        来自Java 6 StringBuilder Javadoc

        该类提供与 StringBuffer 兼容的 API,但不保证同步。此类设计用于在单个线程正在使用字符串缓冲区的地方(通常情况下)用作 StringBuffer 的替代品。在可能的情况下,建议优先使用此类而不是 StringBuffer,因为它在大多数实现下会更快。

        这意味着该类不是线程安全的,您应该更喜欢StringBuffer,因为您知道该变量将被并发访问。

        但是,在这种情况下,您可以保证您的StringBuilder 只能从一个线程访问,因为它是局部变量而不是实例变量。请参阅问题'Thread safety and local variables' 以获得解释。

        【讨论】:

          【解决方案7】:

          StringBuilder 不是线程安全的,但只要您从单个线程中使用它,您就不必担心它。即使您从两个线程进行访问,您也可以通过用同步块封闭关键部分来轻松使其成为线程安全的,例如

          private StringBuilder sb = new StringBuilder();
          
          void appendSomething(String v) {
            synchronized (sb) {
              sb.append("You entered ");
              sb.append(v);
            }
          }
          

          如果整个方法是关键部分,您可以在方法上说同步

          synchronized void appendSomething(String v) {
           sb.append("You entered ");
           sb.append(v);
          }
          

          注意我明确写了两个附加语句来证明仅使用线程安全的 StringBuffer 不会使代码线程安全。如果您使用 StringBuffer 运行两个线程,则每个追加可能会同步,但仍然可能发生竞争条件。

          private StringBuffer sb = new StringBuffer();
          
          void appendSomething(String v) {
           sb.append("You entered ");
           // Race condition!!!
           sb.append(v);
          }
          

          所以写“hello”和“world”的两个线程可能会导致输出“You enter You enter helloworld”,因为每个附加都受到保护,而不是整个操作。

          使用同步类的效率也较低。例如,在上面的示例中,对 append 的两个调用都是同步的,因此除了竞争条件之外,我必须锁定对象两次,而不是使用非同步类锁定一次。

          【讨论】:

            猜你喜欢
            • 2013-02-20
            • 1970-01-01
            • 2011-05-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多