Fundamentals 7 min read

Why Is StringBuilder Not Thread‑Safe? Deep Dive into Java’s Internals

Although StringBuilder and StringBuffer share similar APIs, StringBuilder lacks thread safety because its append method updates shared fields without synchronization, leading to race conditions that can corrupt the internal char array and cause ArrayIndexOutOfBoundsException, as demonstrated by a multithreaded test example.

Senior Brother's Insights
Senior Brother's Insights
Senior Brother's Insights
Why Is StringBuilder Not Thread‑Safe? Deep Dive into Java’s Internals

Reason Analysis

StringBuilder's append method does not use synchronized, while most methods in StringBuffer are declared with the synchronized keyword, providing method‑level locking.

public StringBuilder append(String str) {
    super.append(str);
    return this;
}
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

Exception Example

A test creates a shared StringBuilder, starts ten threads, each appending the character "a" 1,000 times. The expected final length is 10,000, but repeated runs often produce a smaller length and sometimes throw an ArrayIndexOutOfBoundsException.

@Test
public void test() throws InterruptedException {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 10; i++) {
        new Thread(() -> {
            for (int j = 0; j < 1000; j++) {
                sb.append("a");
            }
        }).start();
    }
    // Sleep to ensure all threads finish
    Thread.sleep(1000);
    System.out.println(sb.length());
}

Root Cause of Thread‑Unsafety

StringBuilder inherits two crucial fields from AbstractStringBuilder:

// fields in AbstractStringBuilder
char[] value;
int count;

The append implementation increments count without any atomicity:

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; // non‑atomic update
    return this;
}

When two threads read the same count value, both add the length and write back the same result, causing lost updates and an incorrect final length.

Why the Exception Occurs

Because the stale count may prevent the internal array from expanding, ensureCapacityInternal can skip resizing, and the subsequent String.getChars copies beyond the actual array bounds, triggering the exception.

private void ensureCapacityInternal(int minimumCapacity) {
    if (minimumCapacity - value.length > 0) {
        value = Arrays.copyOf(value, newCapacity(minimumCapacity));
    }
}

The new capacity is calculated as twice the current size plus two:

private int newCapacity(int minCapacity) {
    int newCapacity = (value.length << 1) + 2;
    if (newCapacity - minCapacity < 0) {
        newCapacity = minCapacity;
    }
    return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
        ? hugeCapacity(minCapacity)
        : newCapacity;
}

Conclusion

Understanding that StringBuilder updates the shared count field without synchronization explains its lack of thread safety and why concurrent appends can produce wrong lengths or runtime exceptions. Use StringBuffer or external synchronization when mutable strings are accessed by multiple threads.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaJVMconcurrencythread safetystringbuilder
Senior Brother's Insights
Written by

Senior Brother's Insights

A public account focused on workplace, career growth, team management, and self-improvement. The author is the writer of books including 'SpringBoot Technology Insider' and 'Drools 8 Rule Engine: Core Technology and Practice'.

0 followers
Reader feedback

How this landed with the community

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.