14

我正在构建一个由多个部分组成的字符串,并且想要使用其中一个StringBufferStringBuilder这样做。从 Java 5 文档中,我认为这StringBuilder是最好的,但需要注意的是

的实例StringBuilder对于多线程使用是不安全的。

从这个陈述中,我明白我不应该有一个StringBuilder由多个线程共享的实例。但是这个案例呢:

//Is this safe?
//foo() is called simultaneously by multiple threads
String foo(String a, String b) {
    return new StringBuilder(a).append(b).toString();
}

在这里,函数中可能同时有多个线程,同时使用StringBuilder该类(例如,静态变量的并发访问,如果有的话),但每个线程都有自己单独的StringBuilder. 从文档中,我不能完全确定这是否算作多线程使用。

4

5 回答 5

19

这完全没问题。只要局部变量不访问或改变实例或类变量,它们就不会出现线程安全问题。

于 2009-03-10T18:28:23.767 回答
11

是的,这是安全的,因为 StringBuilder 对象仅在本地使用(每个调用 foo() 的线程都会生成自己的 StringBuilder)。

您还应该注意,您发布的代码实际上与由此生成的字节码相同:

String foo(String a, String b) {
    return a + b;
}
于 2009-03-10T18:29:05.857 回答
6

您拥有的代码是安全的。

这段代码不是。

public class Foo
{
    // safe
    private final static StringBuilder builder;

    public static void foo()
    {
        // safe
        builder = new StringBuilder();
    }

    public static void foo(final String a)
    {
        // unsafe
        builder.append(a);
    }

    public synchronized void bar(final String a)
    {
        // safe
        builder.append(a);
    }
}

仅使用本地数据的局部变量没有线程安全问题。一旦开始处理在类或实例方法/变量级别可见的数据,您只能遇到线程安全问题。

于 2009-03-11T02:38:55.273 回答
4

同意其他答案 - 只是一个注释。

如果存在多个线程正在使用 StringBuffer 的情况,这可能是一个完全被破坏的用例,因为这意味着单个字符串是以准随机顺序构建的,因此使 StringBuffer 成为线程没有意义安全的。

于 2009-03-10T18:32:49.950 回答
3

我不确定是否需要此代码,因为我猜 Java 会自动选择 StringBuilder。如果您没有性能问题,请使用 a + b。

如果需要性能,请尝试:

return new StringBuilder(
a.length() + b.length()).append(a).append(b).toString();

它会正确调整缓冲区的大小,并防止 VM 调整其大小并在途中创建要收集的垃圾。

于 2009-03-10T18:38:01.467 回答