Topic 78 of 119 7. Arrays and Strings in Java Interactive Tutorial

Java StringBuffer: Thread-Safe Mutable String Operations

9 mins read Last updated: 22 Aug 2026 28,494 views

Direct Answer & Core Concept

the String class, whose objects cannot be changed after creation, a StringBuffer object can be modified directly.

The important feature of StringBuffer is that its methods are synchronized, making it suitable for situations where the same mutable text object may be accessed by multiple threads.

For example, if a Java application needs to repeatedly append, insert, delete, or replace text while sharing the same buffer between threads, StringBuffer provides built-in synchronization.

Detailed Explanation & Mechanics

What Is StringBuffer in Java?

StringBuffer is a class in the java.lang package that represents a mutable sequence of characters.

Example:

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Hello");
buffer.append(" Java");
System.out.println(buffer);

Output:

The existing StringBuffer object is modified when append() is called.

You can continue modifying it:

Main.java
Run Online
buffer.append(" Programming");
System.out.println(buffer);

Output:


Why Use StringBuffer?

The main reason to use StringBuffer is when you need a mutable string-like object with synchronized methods.

Consider:

Main.java
Run Online
StringBuffer buffer = new StringBuffer();
buffer.append("Java");
buffer.append(" ");
buffer.append("Programming");
System.out.println(buffer);

The same buffer is modified multiple times.

This is different from immutable String objects.

With String:

Main.java
Run Online
String text = "Java";
text = text + " Programming";

A new string value is produced because String cannot be modified.

With StringBuffer:

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Java");
buffer.append(" Programming");

The existing buffer is changed.


StringBuffer vs String

The most important difference is mutability.

FeatureStringStringBuffer
MutableNoYes
Can modify existing objectNoYes
Thread-safeYes, because immutableYes, through synchronization
Repeated modificationsLess suitableSuitable
Synchronization overheadNot applicableYes
Packagejava.langjava.lang

Example:

Main.java
Run Online
String text = "Hello";
text = text + " World";

The original String cannot be changed.

With StringBuffer:

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Hello");
buffer.append(" World");

The buffer itself is modified.


StringBuffer vs StringBuilder

This is one of the most important comparisons when learning Java strings.

Both classes are mutable.

The major difference is synchronization.

FeatureStringBuilderStringBuffer
MutableYesYes
Synchronized methodsNoYes
Thread-safe for its synchronized operationsNoYes
Single-thread performanceGenerally betterGenerally lower due to synchronization overhead
Multi-thread shared mutable useRequires external synchronization/designProvides synchronized methods
IntroducedJava 5Java 1.0

Example:

Main.java
Run Online
StringBuilder builder = new StringBuilder();

and:

Main.java
Run Online
StringBuffer buffer = new StringBuffer();

Simple rule

Use StringBuilder when synchronization is not needed.

Use StringBuffer when you specifically need its synchronized mutable-string behavior.

Do not choose StringBuffer merely because it is "safer" without considering whether multiple threads actually share the same mutable object.


Creating a StringBuffer

There are several ways to create a StringBuffer.

1. Empty StringBuffer

Main.java
Run Online
StringBuffer buffer = new StringBuffer();

The buffer initially contains no characters.

You can add text:


2. StringBuffer with Initial Text

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Hello");

The buffer starts with:

You can then modify it:

Main.java
Run Online
buffer.append(" Java");
System.out.println(buffer);

Output:


3. StringBuffer with Initial Capacity

You can specify an initial capacity:

Main.java
Run Online
StringBuffer buffer = new StringBuffer(100);

This creates a buffer with an initial capacity of 100 characters.

Capacity and length are different concepts.

Main.java
Run Online
StringBuffer buffer = new StringBuffer(100);
System.out.println(buffer.length());
System.out.println(buffer.capacity());

Output:


append() Method

append() adds content to the end of the buffer.

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Hello");
buffer.append(" Java");
System.out.println(buffer);

Output:

You can append different types of data.

Main.java
Run Online
StringBuffer buffer = new StringBuffer();
buffer.append("Age: ");
buffer.append(35);
buffer.append(", Active: ");
buffer.append(true);
System.out.println(buffer);

Output:


Appending Characters

You can append a single character:

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Java");
buffer.append('!');
System.out.println(buffer);

Output:


Appending Numbers

StringBuffer can append numeric values directly.

Main.java
Run Online
StringBuffer buffer = new StringBuffer();
buffer.append("Price: ");
buffer.append(999);
System.out.println(buffer);

Output:

Floating-point values also work:

Main.java
Run Online
buffer.append(" Discount: ");
buffer.append(10.5);

insert() Method

The insert() method adds content at a specific position.

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Hello World");
buffer.insert(6, "Java ");
System.out.println(buffer);

Output:

The syntax is:

The inserted content begins at the specified index.


insert() with a Character

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Jva");
buffer.insert(1, 'a');
System.out.println(buffer);

Output:


delete() Method

The delete() method removes characters between two indexes.

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Hello Java");
buffer.delete(5, 10);
System.out.println(buffer);

Output:

Remember:

The start index is included, while the end index is excluded.


deleteCharAt() Method

To remove one character, use deleteCharAt().

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Java");
buffer.deleteCharAt(3);
System.out.println(buffer);

Output:

The character at index 3 was removed.


replace() Method

The replace() method replaces characters within a specified range.

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Hello World");
buffer.replace(6, 11, "Java");
System.out.println(buffer);

Output:

Syntax:

Main.java
Run Online
replace(start, end, newText)

reverse() Method

The reverse() method reverses the characters in the buffer.

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Java");
buffer.reverse();
System.out.println(buffer);

Output:

This makes StringBuffer useful for simple reverse-string and palindrome exercises.


charAt() Method

charAt() returns the character at a specified index.

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Java");
System.out.println(buffer.charAt(2));

Output:

Indexes start from zero:

Main.java
Run Online
J → 0a → 1v → 2a → 3

setCharAt() Method

setCharAt() changes a character at a particular index.

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Jova");
buffer.setCharAt(1, 'a');
System.out.println(buffer);

Output:

This demonstrates the mutable nature of StringBuffer.


length() Method

The length() method returns the number of characters currently stored.

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Java");
System.out.println(buffer.length());

Output:

After appending more text:

Main.java
Run Online
buffer.append(" Programming");
System.out.println(buffer.length());

the length increases accordingly.


capacity() Method

capacity() returns the current amount of storage available before the buffer needs to expand.

Main.java
Run Online
StringBuffer buffer = new StringBuffer();
System.out.println(buffer.capacity());

The default initial capacity is commonly 16.

You can specify your own:

Main.java
Run Online
StringBuffer buffer = new StringBuffer(100);
System.out.println(buffer.capacity());

Output:


Capacity vs Length

These concepts should not be confused.

Main.java
Run Online
StringBuffer buffer = new StringBuffer(50);
buffer.append("Java");
System.out.println("Length: " + buffer.length());
System.out.println("Capacity: " + buffer.capacity());

Output:

Length

The number of characters currently stored.

Capacity

The amount of internal storage currently available before the buffer needs to grow.


ensureCapacity() Method

ensureCapacity() ensures that the buffer has at least the specified capacity.

Main.java
Run Online
StringBuffer buffer = new StringBuffer();
buffer.ensureCapacity(100);
System.out.println(buffer.capacity());

This can be useful when you know that a large amount of text will be added.

Providing a reasonable initial capacity can reduce the number of internal resizing operations.


setLength() Method

setLength() changes the current length of the buffer.

For example:

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Hello");
buffer.setLength(3);
System.out.println(buffer);

Output:

The extra characters were removed.

If the requested length is larger than the current length, additional null characters are introduced into the buffer.


toString() Method

toString() converts the StringBuffer contents into a normal immutable String.

Main.java
Run Online
StringBuffer buffer = new StringBuffer();
buffer.append("Hello");
buffer.append(" Java");
String result = buffer.toString();
System.out.println(result);

Output:

This is commonly used when the final result needs to be passed to a method or API that expects a String.


StringBuffer in a Loop

StringBuffer can be used to build text repeatedly.

Main.java
Run Online
StringBuffer buffer = new StringBuffer();
for (int i = 1;
i <= 10;
i++) {
    buffer.append(i).append(" ");
}System.out.println(buffer);

Output:

This is more appropriate than repeatedly modifying immutable strings when there is substantial text construction.


Method Chaining

Many StringBuffer methods return the same buffer, so operations can be chained.

Main.java
Run Online
StringBuffer buffer = new StringBuffer();
buffer.append("Java") .append(" ") .append("Programming") .append(" ") .append("Language");
System.out.println(buffer);

Output:

Main.java
Run Online
Java Programming Language

Method chaining can make repeated append operations concise.


StringBuffer and Thread Safety

Thread safety is the key feature that distinguishes StringBuffer from StringBuilder.

StringBuffer provides synchronized methods for many of its operations.

For example:

Main.java
Run Online
StringBuffer buffer = new StringBuffer();
buffer.append("Hello");
buffer.append(" World");

The methods are synchronized, which helps coordinate access when multiple threads operate on the same buffer.

However, an important point is:

Synchronizing individual methods does not automatically make every multi-step sequence of operations atomic.

For example:

Main.java
Run Online
if (buffer.length() > 0) {
    buffer.deleteCharAt(0);
}

The check and deletion are two separate operations. If several threads share the same buffer, more careful synchronization may still be required around the complete operation depending on the application's requirements.


Simple Multithreading Example

Consider two threads writing to the same StringBuffer.

Main.java
Run Online
class MyTask extends Thread {
    private StringBuffer buffer;
    MyTask(StringBuffer buffer) {
        this.buffer = buffer;
    } @Override public void run() {
        for (int i = 1;
        i <= 5;
        i++) {
            buffer.append(i).append(" ");
        }
    }
}public class Main {
    public static void main(String[] args) throws InterruptedException {
        StringBuffer buffer = new StringBuffer();
        Thread t1 = new MyTask(buffer);
        Thread t2 = new MyTask(buffer);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println(buffer);
    }
}

Both threads use the same StringBuffer.

The synchronized methods provide protection for the individual buffer operations.

The exact output order between threads is not guaranteed.


Important Thread-Safety Lesson

Thread safety does not mean that the output order is predictable.

For example, two threads may produce different valid orderings of their appended values.

The important distinction is:

Main.java
Run Online
Thread-safe ≠Predictable execution order

Thread scheduling is controlled by the runtime and operating system.


StringBuffer and String Pool

StringBuffer is not itself a String Pool object.

For example:

Here "Java" is a string literal.

But:

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Java");

creates a mutable StringBuffer object initialized using that text.

When you call:

Main.java
Run Online
String result = buffer.toString();

you obtain a String.


Converting String to StringBuffer

You can initialize a StringBuffer using a String.

Main.java
Run Online
String text = "Hello Java";
StringBuffer buffer = new StringBuffer(text);
buffer.append(" Programming");
System.out.println(buffer);

Output:


Converting StringBuffer to String

Use toString().

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Hello Java");
String text = buffer.toString();
System.out.println(text);

This is the normal way to obtain an immutable String representation of the buffer.


Reverse a String Using StringBuffer

Main.java
Run Online
String text = "Programming";
StringBuffer buffer = new StringBuffer(text);
buffer.reverse();
System.out.println(buffer);

Output:


Check Palindrome Using StringBuffer

A palindrome reads the same from left to right and right to left.

Examples:

Java example:

Main.java
Run Online
public class PalindromeExample {
    public static void main(String[] args) {
        String text = "level";
        StringBuffer buffer = new StringBuffer(text);
        buffer.reverse();
        if (text.equals(buffer.toString())) {
            System.out.println("Palindrome");
        } else {
            System.out.println("Not a palindrome");
        }
    }
}

Output:


Building a Comma-Separated List

StringBuffer can be used to create formatted text.

Main.java
Run Online
StringBuffer buffer = new StringBuffer();
for (int i = 1;
i <= 5;
i++) {
    buffer.append(i);
    if (i < 5) {
        buffer.append(", ");
    }
}System.out.println(buffer);

Output:

This avoids having to remove a trailing comma afterward.


Creating a Sentence

Main.java
Run Online
StringBuffer sentence = new StringBuffer();
sentence.append("Java");
sentence.append(" is");
sentence.append(" a");
sentence.append(" popular");
sentence.append(" programming");
sentence.append(" language.");
System.out.println(sentence);

Output:

Main.java
Run Online
Java is a popular programming language.

Generating HTML with StringBuffer

A StringBuffer can also construct dynamic text such as simple HTML.

Main.java
Run Online
StringBuffer html = new StringBuffer();
html.append("<html>");
html.append("<body>");
html.append("<h1>Hello Java</h1>");
html.append("</body>");
html.append("</html>");
System.out.println(html);

For larger applications, dedicated template engines are usually more maintainable than manually constructing large HTML documents.


StringBuffer and SQL

A buffer can technically be used to construct SQL text:

Main.java
Run Online
StringBuffer query = new StringBuffer();
query.append("SELECT name ");
query.append("FROM users ");
query.append("WHERE age > 18");
System.out.println(query);

Output:

Main.java
Run Online
SELECT name FROM users WHERE age > 18

However, never build SQL using untrusted user input through simple string concatenation.

For database applications, use parameterized queries or prepared statements to protect against SQL injection.


StringBuffer Performance

StringBuffer is designed for mutable character manipulation, but its synchronization introduces overhead compared with StringBuilder.

For a typical single-threaded operation:

Main.java
Run Online
StringBuilder builder = new StringBuilder();

is generally preferred when no synchronization is required.

For a shared mutable buffer where synchronized methods are specifically useful:

Main.java
Run Online
StringBuffer buffer = new StringBuffer();

may be appropriate.

The actual performance difference depends on the workload, Java implementation, runtime optimizations, and how the objects are used.


Should You Always Use StringBuffer?

No.

Choosing StringBuffer only because it is synchronized is not automatically the best design.

Ask:

  1. Is the text modified repeatedly?

  2. Is the mutable object shared between threads?

  3. Do I need the synchronized behavior provided by StringBuffer?

  4. Would a thread-local StringBuilder or another design avoid shared mutable state?

If the code is single-threaded, StringBuilder is often the simpler choice.


String, StringBuilder, and StringBuffer

This is an important Java concept.

Main.java
Run Online
String↓Immutable↓Cannot modify existing objectStringBuilder↓Mutable↓Not synchronizedStringBuffer↓Mutable↓Synchronized methods

A practical comparison:

FeatureStringStringBuilderStringBuffer
MutableNoYesYes
Thread-safe mutable operationsNot applicableNoYes, through synchronization
Best for repeated modificationsNot usuallyYesYes
Synchronization overheadNoNoYes
Typical single-thread choiceYes for simple textYes for repeated buildingUsually unnecessary
Shared mutable textImmutable designRequires careProvides synchronization for its methods

Common StringBuffer Mistakes

1. Confusing StringBuffer with String

This:

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Java");

does not create an immutable String.

The buffer remains mutable.


2. Assuming Thread Safety Means Everything Is Atomic

Individual synchronized operations do not automatically make a sequence of multiple operations atomic.

Be careful with compound operations.


3. Using StringBuffer in Every Program

If your application is single-threaded and simply needs efficient string construction, StringBuilder is often more appropriate.


4. Ignoring Index Boundaries

This can cause an exception:

Main.java
Run Online
StringBuffer buffer = new StringBuffer("Java");
buffer.charAt(10);

Valid indexes are:


5. Confusing Capacity and Length

means current number of characters.

means current internal capacity.

They are not the same thing.


Best Practices for StringBuffer

1. Use It When Synchronized Mutable Operations Are Needed

If multiple threads genuinely share a mutable character sequence, StringBuffer can be useful.

2. Prefer StringBuilder When Synchronization Is Unnecessary

Do not pay synchronization overhead without a reason.

3. Use toString() for the Final String

Main.java
Run Online
String result = buffer.toString();

4. Provide an Initial Capacity When the Size Is Predictable

Main.java
Run Online
StringBuffer buffer = new StringBuffer(1000);

This can reduce resizing when you know the approximate amount of content.

5. Be Careful with Compound Operations

Synchronization of individual methods does not make a multi-operation algorithm automatically atomic.


Important StringBuffer Methods

MethodPurpose
append()Adds content to the end
insert()Inserts content at an index
delete()Deletes a range
deleteCharAt()Deletes one character
replace()Replaces a range
reverse()Reverses the characters
charAt()Reads a character
setCharAt()Changes a character
length()Returns current length
capacity()Returns current capacity
ensureCapacity()Ensures minimum capacity
setLength()Changes current length
toString()Converts to String

Complete StringBuffer Example

Main.java
Run Online
public class StringBufferExample {
    public static void main(String[] args) {
        StringBuffer buffer = new StringBuffer();
        // Append
        buffer.append("Java");
        // Add more text
        buffer.append(" Programming");
        System.out.println("After append: " + buffer);
        // Insert
        buffer.insert(5, "Language ");
        System.out.println("After insert: " + buffer);
        // Replace
        buffer.replace(0, 4, "Advanced Java");
        System.out.println("After replace: " + buffer);
        // Delete
        buffer.delete(0, 9);
        System.out.println("After delete: " + buffer);
        // Reverse
        buffer.reverse();
        System.out.println("After reverse: " + buffer);
        // Convert to String
        String result = buffer.toString();
        System.out.println("Final String: " + result);
    }
}

This example demonstrates the most important StringBuffer operations in one program.


Real-World Use Cases

StringBuffer can be useful in situations such as:

Multi-threaded text construction

Multiple threads may need to work with the same mutable character sequence.

Dynamic message construction

Applications can build messages from multiple pieces.

Legacy Java applications

Older Java applications may already use StringBuffer.

Shared mutable text

When synchronized methods on a mutable character sequence fit the application design.

However, modern applications should still consider whether sharing mutable state is necessary at all.


Frequently Asked Questions

What is StringBuffer in Java?

StringBuffer is a mutable sequence of characters that provides synchronized methods for modifying its contents.

Is StringBuffer mutable?

Yes. You can modify its contents after creation.

Is StringBuffer thread-safe?

Its methods are synchronized, providing thread-safe behavior for individual operations on the same buffer.

Is StringBuffer faster than StringBuilder?

Usually not for single-threaded work. StringBuilder generally has less synchronization overhead.

What is the difference between StringBuffer and StringBuilder?

Both are mutable. StringBuffer provides synchronization, while StringBuilder does not.

What is the difference between String and StringBuffer?

String is immutable, while StringBuffer is mutable.

How do I reverse a StringBuffer?

Use:

How do I convert StringBuffer to String?

Use:

Main.java
Run Online
String result = buffer.toString();

What does append() do?

It adds content to the end of the existing buffer.

What does insert() do?

It inserts content at a specified index.

What does capacity() mean?

It represents the current amount of internal storage available before the buffer needs to grow.

Is StringBuffer synchronized?

Yes. Its methods are synchronized.

Should I use StringBuffer instead of StringBuilder?

Only when the synchronization provided by StringBuffer is actually useful for your application. For ordinary single-threaded string construction, StringBuilder is generally preferred.


Practice Questions

Beginner

  1. What is StringBuffer in Java?

  2. Is StringBuffer mutable?

  3. What does append() do?

  4. What does reverse() do?

  5. What does length() return?

  6. What does capacity() return?

Intermediate

  1. Write a Java program to reverse a string using StringBuffer.

  2. Write a program to check whether a word is a palindrome.

  3. Use append() to create a sentence.

  4. Use insert() to add text to an existing sentence.

  5. Use delete() to remove a portion of a string.

  6. Use setCharAt() to change a character.

Advanced

  1. Why is StringBuffer synchronized?

  2. What is the difference between StringBuilder and StringBuffer?

  3. Why can StringBuilder be faster than StringBuffer?

  4. Does synchronization of individual methods make a multi-step operation atomic?

  5. Explain the difference between capacity and length.

  6. When would you choose StringBuffer instead of StringBuilder?


Quick Revision

Remember these important points:

  • StringBuffer is mutable.

  • It belongs to the java.lang package.

  • Its methods are synchronized.

  • It is designed for mutable character sequences.

  • append() adds content.

  • insert() inserts content.

  • delete() removes a range.

  • deleteCharAt() removes one character.

  • replace() replaces a range.

  • reverse() reverses the buffer.

  • charAt() reads a character.

  • setCharAt() changes a character.

  • length() returns the current number of characters.

  • capacity() returns the current internal capacity.

  • toString() converts the buffer into a String.

  • StringBuffer generally has more synchronization overhead than StringBuilder.

  • StringBuilder is usually preferred when thread synchronization is not required.

  • Synchronizing individual methods does not automatically make a sequence of multiple operations atomic.


Graphic and Design Ideas

Graphic 1: String vs StringBuilder vs StringBuffer

Create a three-column comparison:

Architecture Diagram
┌─────────────┬────────────────┬─────────────────┐
│   String    │ StringBuilder  │  StringBuffer   │
├─────────────┼────────────────┼─────────────────┤
│ Immutable   │ Mutable        │ Mutable         │
│ No sync     │ No sync        │ Synchronized    │
│ Simple text │ Fast building  │ Shared mutable  │
└─────────────┴────────────────┴─────────────────┘

Graphic 2: StringBuffer Workflow

Main.java
Run Online
Create StringBuffer↓append()↓insert()↓replace()↓delete()↓reverse()↓toString()↓Final String

Graphic 3: Thread-Safety Concept

Show two threads accessing a shared buffer:

Architecture Diagram
Thread 1 ──────┐
↓
StringBuffer
               ↑
Thread 2 ──────┘

       synchronized
          methods

The graphic should explain that synchronization protects individual operations; it should not imply that thread execution order is guaranteed.


Graphic 4: Mutable String Concept

Main.java
Run Online
String"Java"↓modificationNew String valueStringBuffer"Java"↓append()"Java Programming"↓append()"Java Programming Language"

The visual should emphasize that StringBuffer is mutable.

Runnable Code Example: Java StringBuffer

Java 17+
Main.java
Run Online
public class StringBufferDemo {
    public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("Concurrent");
        sb.append(" Safe Buffer");
        System.out.println("Buffer content: " + sb.toString());
        System.out.println("Capacity: " + sb.capacity());
    }
}

Common Java Technical Interview Questions & Answers

Interview Prep
Q1

What is the difference between StringBuffer and StringBuilder?

StringBuffer is thread-safe (synchronized methods) with performance overhead; StringBuilder is not thread-safe but much faster in single-threaded contexts.
Q2

When should you use StringBuffer today?

Only when multiple threads concurrently read and mutate the exact same mutable string buffer instance without external locking.

Key Takeaways, Best Practices & Clean Code Rules

Java Best Practice & Production Rules

Default to StringBuilder for virtually all string construction tasks, as concurrent string manipulation is rare in modern architecture.