Strings
StringBuffer
Explore StringBuffer's thread-safe design, synchronized method overheads, and comparison with StringBuilder.
Interview: Focuses on method synchronizations, thread safety guarantees, and stack-allocation thread lock escape optimizations.
The StringBuffer class is a thread-safe, mutable sequence of characters. It shares the same buffer resizing logic and API methods as StringBuilder. However, to ensure safety in multi-threaded environments, all public methods in StringBuffer are marked with the synchronized keyword, enforcing lock acquisition.
Core Idea
A thread-safe, synchronized mutable character sequence that allows concurrent append operations.
Why It Matters
Methods are synchronized. Modern JVM JIT compilers optimize local configurations via Lock Elision if escape analysis confirms thread isolation.
Interview Lens
Focuses on thread-safety mechanisms, synchronization costs, escape analysis, and lock elision.
JIT Optimizations: Lock Elision
Because public methods are synchronized, StringBuffer is slower than StringBuilder. However, the JIT compiler uses Escape Analysis to optimize this at runtime:
If the JIT compiler determines that a StringBuffer instance is local to a single method and cannot escape to other threads, it performs Lock Elision—meaning it removes the synchronization locks at runtime, matching the speed of a StringBuilder.
Even with this optimization, developers should explicitly choose the correct class at compile time rather than relying on JVM runtime optimizations.
Common Pitfalls
- Defaulting to StringBuffer: Using StringBuffer by default for local method variables where thread safety is not needed, introducing unnecessary lock evaluation checks.
- Assuming Atomic Sequences: Assuming multiple sequential calls are thread-safe without external locks (e.g.
sb.append("A"); sb.append("B");can still be interleaved by other threads unless synchronized externally). - GC overhead: Creating a new instance in hot loops, causing heap allocations.
Best Practices
- Use
StringBuilderby default for all local operations where thread safety is not required. - Use
StringBufferonly when a mutable string builder must be shared and modified concurrently across multiple threads. - Enclose multiple append sequences in synchronized blocks when atomicity is required.
Interview-Relevant Information
Q1: What is Lock Elision?
Answer: Lock Elision is a JIT compiler optimization. If escape analysis shows that an object containing synchronized locks (like a local StringBuffer) is confined to a single method and cannot be accessed by other threads, the compiler strips out the synchronization locks at runtime to boost performance.
Q2: Is a series of appends on a shared StringBuffer thread-safe without external locks?
Answer: Each individual append() call is thread-safe and atomic. However, a sequence of calls (e.g., sb.append("A").append("B")) is not atomic as a whole. Other threads can interleave their appends between "A" and "B", scrambling the final string unless the shared StringBuffer is locked externally.
Quick Checklist
Can you explain synchronized method overheads, describe JIT escape analysis and lock elision, write atomic append blocks, and choose between builder classes? If yes, you understand StringBuffer.
Use Cases
Constructing shared log builders in multi-threaded background workers.
Assembling dynamic buffers in legacy concurrent applications.
Common Mistakes
Using StringBuffer for local variables where StringBuilder is appropriate.
Assuming multiple sequential appends are atomic without external synchronization.