views:

1344

answers:

5

I am building up a String out of multiple pieces and want to use either StringBuffer or StringBuilder to do so. From the Java 5 docs, I see that StringBuilder is preferred when possible, with the caveat that "Instances of StringBuilder are not safe for use by multiple threads". From this statement I understand that I should not have a single StringBuilder instance shared by multiple threads. But what about this case:

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

Here there could be multiple threads in the function at the same time, using the StringBuilder class at the same time (eg, concurrent access of static variables, if there are any), but each thread would have its own separate instance of StringBuilder. From the documentation I can not quite decide whether this counts as use by multiple threads or not.

Any help to clarify this would be appreciated.

+8  A: 

That's perfectly fine. Local variables have no problems with thread safety as long as they don't access or mutate instance or class variables.

Michael Myers
+3  A: 

Yes, that is safe, because the StringBuilder object is used only locally (each thread calling foo() will generate its own StringBuilder).

You should also note that the code you posted is practically identical to the bytecode generated by this:

String foo(String a, String b) {
    return a + b;
}
Kip
How do you see that bytecode?
OscarRyz
@Oscar: javap -c <classname>
Michael Myers
see also: http://stackoverflow.com/questions/272535/how-do-i-decompile-java-class-files
Kip
well ok not identical, it has one extra instruction.. the compiler converts + operator to: new StringBuilder().append(a).append(b);
Kip
+3  A: 

Agree with the other answers--just a note.

If there was a case where StringBuffer was being used by multiple threads, it's probably a completely broken use case because it would mean a single string was being built up in a quasi-random order, so it wouldn't make sense to make StringBuffer thread safe.

Bill K
That's the rationale of StringBuilder. Most of the times the synchronization was not needed.
OscarRyz
Yes, which makes you wonder why they didn't just rewrite StringBuffer instead of creating the parallel StringBuilder. To keep backwards compatibility for that app that builds nondeterministic strings?
Steve B.
Maybe if you were using a StringBuilder for some kind of in-memory logging of a multithreaded app? Not sure why you'd do that though...
Kip
@Kip That's the only thing I could come up with either, and when I tried to justify it, it seemed like a broken use case which fit my original statement so I left it out :)
Bill K
yeah, and if you really wanted to do that a Vector<String> or synchronized ArrayList<String> would probably be more appropriate than a StringBuilder
Kip
+1  A: 

I am not sure if this code is needed, because Java picks the StringBuilder automatically I guess. If you do not have a performance problem, go with a + b.

In case of a performance need, try that:

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

It correctly sizes the buffer and prevents the VM from resizing it and creating garbage to collect on the way.

ReneS
+2  A: 

The code you have is safe.

This code is not.

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

    static
    {
        // 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);
    }
}

Local variables that only make use of local data do not have threadsafe issues. You can only have threadsafe issues once you start dealing with data that is visible at the class or instance method/variable level.

TofuBeer