Fundamentals 7 min read

Why StringBuilder Is Not Thread‑Safe and How It Differs from StringBuffer

This article explains the internal implementation of Java's StringBuilder and StringBuffer, demonstrates how concurrent appends cause incorrect lengths and occasional ArrayIndexOutOfBoundsException, and shows why StringBuffer remains thread‑safe by using synchronized methods.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Why StringBuilder Is Not Thread‑Safe and How It Differs from StringBuffer

Introduction

The interview question asks about the difference between StringBuilder and StringBuffer. The short answer is that StringBuilder is not thread‑safe while StringBuffer is.

Analysis

Both classes share the same internal structure as String: a mutable char[] array and a int count that tracks used characters. The key difference is that StringBuilder does not synchronize its operations.

Below is a multithreaded test that appends characters to a single StringBuilder instance:

public class StringBuilderDemo {
    public static void main(String[] args) throws InterruptedException {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < 10; i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int j = 0; j < 1000; j++){
                        stringBuilder.append("a");
                    }
                }
            }).start();
        }
        Thread.sleep(100);
        System.out.println(stringBuilder.length());
    }
}

Running this code creates ten threads, each appending 1,000 characters. The expected length is 10,000, but the actual output is often smaller (e.g., 9,326) and may throw an ArrayIndexOutOfBoundsException .

1. Why the output differs from the expectation

The count += len statement in AbstractStringBuilder.append is not atomic. When two threads read the same count value concurrently, both compute the same new value and write it back, causing lost updates and a final length smaller than 10,000.

2. Why an ArrayIndexOutOfBoundsException may be thrown

The method ensureCapacityInternal checks whether the internal char[] needs to grow. If so, it calls expandCapacity , which creates a new array with roughly double the previous size and copies the old contents using Arrays.copyOf . The subsequent str.getChars copies characters into the value array at position count . If another thread has already increased count after the capacity check, the copy may write beyond the array bounds, triggering the exception.

The relevant source snippets are shown below:

// fields in AbstractStringBuilder
char[] value;
int count;
public StringBuilder append(String str) {
    super.append(str);
    return this;
}
public AbstractStringBuilder append(String str) {
    if (str == null) return appendNull();
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
    if (minimumCapacity - value.length > 0)
        expandCapacity(minimumCapacity);
}
void expandCapacity(int minimumCapacity) {
    int newCapacity = value.length * 2 + 2;
    // ... other checks omitted
    value = Arrays.copyOf(value, newCapacity);
}
public static char[] copyOf(char[] original, int newLength) {
    char[] copy = new char[newLength];
    System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
    return copy;
}

When two threads interleave these steps, the non‑atomic update of count and the separate capacity check can lead to both a wrong final length and an out‑of‑bounds copy.

Replacing StringBuilder with StringBuffer in the test yields the correct length of 10,000 because all mutating methods in StringBuffer are synchronized, making the updates atomic and preventing the race conditions described above.

Thus, the lack of synchronization in StringBuilder explains its thread‑unsafe behavior, while StringBuffer guarantees thread safety through synchronized methods.

JavaconcurrencyThread SafetyStringBuilderStringBuffer
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.