views:

109

answers:

7

Consider the below struts Action class in which, I am using a StringBuilder variable inside the execute method. My question: Is the variable sb threadsafe or not?

public DemoAction extends Action
{
    ......

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

What if the same variable sb declared outside the execute(). Remember there will be only one object for DemoAction in WebContainer.?

+11  A: 

Local variables are thread safe, as long as no other thread somehow gets a reference to the same string builder instance, it’s thread safe.

Konrad Rudolph
+1 for "as long as you don't pass the reference around"
Thilo
A: 

From the spec: Instances of StringBuilder are not safe for use by multiple threads. If such synchronization is required then it is recommended that StringBuffer be used.

But as Konrad Rudolph pointed out... in your case it's a local variable so you should be fine

Jeroen Rosenberg
There is virtually no time ever that StringBuffer or other synchronized collections like Vector make sense. Chances are that if I have two threads trying to access a string buffer or a list that I need to identify and synchronize a critical section. It is likely that the critical section is going to need to encompass more than one method call.
locka
+2  A: 

Yes, local variables are inherently thread-safe. Every thread gets its own copy.

Thilo
Every call, even.
gustafc
"as long as you don't pass the reference around". Thanks, Konrad.
Thilo
+2  A: 

It is threadsafe because you only create and use it in the scope of the method so reference will be stored in stack space which is local for each thread

iYasha
A: 

It is safe. This variable is local to execute() method and is created every time this method is called, so in multithread environment every thread can have its own, separate copy of sb variable.

Michał Niklas
A: 

From the Java 6 StringBuilder Javadoc:

"This class provides an API compatible with StringBuffer, but with no guarantee of synchronization. This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations."

This means that the class is not threadsafe, and you should prefer StringBuffer where you know the variable will be accessed concurrently.

However, you can guarantee in this case that your StringBuilder will be accessed only from one thread, because it is local variable rather than an instance variable. See the question 'Thread safety and local variables' for an explanation.

isme
A: 

StringBuilder isn't thread safe, but as long as you use it from a single thread you don't have to worry about it. Even if you do access from two threads you can easily make it thread safe by enclosing the critical section with a synchronized block, e.g.

private StringBuilder sb = new StringBuilder();

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

If the entire method is the critical section you can say synchronized on the method

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

Note I explicitly wrote two append statements to demonstrate that just using thread safe StringBuffer wouldn't make code thread safe. If you ran two threads with a StringBuffer then each append might be synchronized but it would still be possible for race conditions to occur.

private StringBuffer sb = new StringBuffer();

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

So two threads writing "hello" and "world" might result in the output "You entered You entered helloworld" because each append is protected not the whole action.

Using synchronized classes are also less efficient. For example in the above example, both calls to append are synchronized so in addition to a race condition I have to lock the object twice compared to once with the non-synchronized class.

locka