14

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.

4
  • there might be some benefit in making foo() a static method as well, since it doesn't touch any instance variables. Commented Mar 10, 2009 at 18:30
  • @Kip: Depends on the class. But some times you may want to perform polymorphic operations and making the method static will imped this. Commented Mar 10, 2009 at 18:33
  • Using String.concat would faster, but I think this is just an example. Commented Mar 10, 2009 at 18:35
  • might be useful: How do I prove programmatically that StringBuilder is not threadsafe? Commented Feb 19, 2018 at 10:24

5 Answers 5

19

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.

Sign up to request clarification or add additional context in comments.

Comments

11

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;
}

3 Comments

well ok not identical, it has one extra instruction.. the compiler converts + operator to: new StringBuilder().append(a).append(b);
Woah! I wouldn't have believed that unless I tried it. The only difference is there is additonal .append call in this answer, one for each argument. Hmm.
6

The code you have is safe.

This code is not.

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);
    }
}

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.

Comments

4

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.

8 Comments

That's the rationale of StringBuilder. Most of the times the synchronization was not needed.
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?
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 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 :)
There is memory overhead for every object in those lists. A StringBuffer allows you to cut down on memory usage in lieu of more synchronized calls.
|
3

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.