What does synchronization means in terms of StringBuilder and StringBuffer classes?

9.5k views Asked by At

I am quite confused with the term 'synchronized', I've got following from java documentation.

A mutable sequence of characters. 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.

As I know synchronization relates to threads and the way of their access.

Lets say, I have a web application that is utilizing StringBuilder in one of its methods,

  • What does no guarantee of synchronisation mean here?
  • Should I be worried about anything? When should I be worried about multiple threads? Any examples?
  • When should I care about guaranteed and non-guaranteed synchronisation?
  • What is an example of having a web application with multiple threads?

An example would be highly appreciated.

Please note I know multiple thread access require synchronization because they need to have access to the same data! I need to have an example for that.

7

There are 7 answers

1
prmottajr On

You should care about it when you have a StringBuffer that is shared berween threads. If you are not sharing thus no race condition van happen and you are free to use StringBuilder.

0
kanchan shegar On

The synchronized keyword doesn't show up in the generated JavaDoc, but if you open the source code of StringBuffer, you'll see that each public method which can change the state of the instance actually has synchronized keyword in its signature.

For example the getChars method

   /**
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    @Override
    public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
                                      int dstBegin)
    {
        super.getChars(srcBegin, srcEnd, dst, dstBegin);
    }
0
regina_fallangi On

Imagine you have a variable myElement as a StringBuffer. Your application has a news feed from different newspapers, and you have multiple threads filling that up from various sources. Threads will locate their new information in the DOM element that myElement describes. Once they locate it, they modify myElement, so other thread knows where to locate the new piece of news. Thanks to synchronization, a thread will block another one when they have access to the same variable, but not in this case, so it can happen that one thread reads myElement when it is being modified and is half complete, and gets a reference to a part of the DOM that does not exist.

0
A.v On

Think about it this way. Let's say you have a class which share an instance of StringBuilder between it's method. Something like this:

public class MyClass {
    private StringBuilder str = new StringBuilder();

    public void add(String str) {
         this.str.append(str);
    }

    public void remove(int start, int end) {
         this.str.delete(start, end);
    }

}

Because this instance is share between non-synchronized method so if two threads at the same time call this methods the data won't be the data you are expected. It is the meaning of not guaranteed synchronization.

Instead of using StringBuilder you can use StringBuffer which supports synchronization.

public class MyClass {
    private StringBuffer str = new StringBuffer();

    public void add(String str) {
         this.str.append(str);
    }

    public void remove(int start, int end) {
         this.str.delete(start, end);
    }

}

As you know synchronization has some performance issues but it is necessary in case of multi threading.

Usually StringBuilder can be used as local variables.

1
assylias On

Using StringBuffer almost never makes sense:

  • most of the time, you can use a local StringBuilder variable and there is only one thread involved so no synchronzation is required
  • in the rare cases where the StringBuffer/Builder variable is a field and is shared across threads, the StringBuffer guarantee will probably not be enough anyway because each call to append will be ordered randomly

Imagine:

public void m(String a, String b) {
  sharedStringBuffer.append(a).append(b);
}

StringBuffer doesn't give you the guarantee that each call to m will result in a and b to be adjacent as another call to append may have happened in the middle...

So bottom line:

  • either the variable is not shared: use a StringBuilder
  • either it is shared and you probably need more than the synchronization of StringBuffer: use a StringBuilder with appropriate synchronization.
6
Eran On

You should care about synchronization if more than one thread can have access to the same StringBuilder instance at the same time. In such case you should consider using StringBuffer instead.

For example, here you should consider using a StringBuffer instead of StringBuilder :

public class Test implements Runnable
{
    public static StringBuilder sb = new StringBuilder();

    public void run ()
    {
        Test.sb.append ("something");
    }

    public static void main (String[] args)
    {
        // start two threads
        new Thread (new Test()).start();
        new Thread (new Test()).start();
    }
}

If you have a StringBuilder instance which is local to some method, there is no risk of another thread accessing it, so you don't need synchronization, and using StringBuilder would be more efficient.

0
AudioBubble On

StringBuffer is not needed unless you are sharing it between threads, in which case, synchronization makes sense. StringBuilder is mutable, which means it's state can be viewed inconsistently between threads. StringBuffer does not suffer from this problem (should it need to at all).

StringBuilder is like StringBuffer v2. It was added to the Java libraries after the phase where developers were paranoid about thread-safety and required thread safety when they did not need it.

As for the bolded portion of the javadoc you posted, synchronization has overhead, and because StringBuilder is non-synchronized, it does not take a performance hit.

The synchronization guarantee means that because it is "compatible with StringBuffer", you may expect StringBuilder to be synchronized, but that may not be the case (such as when the JIT optimizes StringBuffer, for example).

You should not worry about non-guaranteed or guaranteed synchronization. What you should worry about is using StringBuffer when it is shared. Whether or not StringBuilder is synchronized or not synchronized, as long as it is shared only within one thread or protected accordingly, you should not encounter any problems.

You should worry about using StringBuffer here:

final StringBuffer append = new StringBuffer();

void append() {
    append.append(". ");
}

new Thread(() -> append()).start();
new Thread(() -> append()).start();

You can see that it is accessed by two threads. Notice how it declared final for initialization safety.