StringBuffer in Java
Learn the thread-safe way to build strings
💡 Think of StringBuffer like a shared whiteboard in a classroom! Multiple students (threads) can use it, but only ONE can write at a time. This prevents chaos and makes sure everyone's writing is clear. StringBuilder is like a personal notepad - faster, but not safe for sharing!
🔒 What is StringBuffer?
StringBuffer is a thread-safe, mutable sequence of characters. It's exactly like StringBuilder, but with synchronized methods that make it safe to use when multiple threads need to modify the same string. This safety comes with a small performance cost.
public class StringBufferBasics { public static void main(String[] args) { // Creating StringBuffer (exactly like StringBuilder!) StringBuffer sb = new StringBuffer("Hello"); // All the same methods work sb.append(" World"); System.out.println(sb); // Hello World sb.insert(6, "Beautiful "); System.out.println(sb); // Hello Beautiful World sb.reverse(); System.out.println(sb); // dlroW lufituaeB olleH // The difference? All methods are SYNCHRONIZED // This makes it safe for multiple threads to use // but slightly slower than StringBuilder }}⚖️ StringBuilder vs StringBuffer
| Aspect | StringBuilder | StringBuffer |
|---|---|---|
| Thread Safety | NOT thread-safe | Thread-safe (synchronized) |
| Performance | Faster (no synchronization overhead) | Slower (synchronization overhead) |
| When to Use | Single-threaded applications (most cases) | Multi-threaded applications sharing same object |
Rule of thumb: Use StringBuilder by default. Only use StringBuffer when multiple threads will access the same object.
🔒 Thread Safety in Action
public class ThreadSafetyExample { public static void main(String[] args) throws InterruptedException { // UNSAFE: StringBuilder with multiple threads StringBuilder unsafeSB = new StringBuilder(); Thread t1 = new Thread(() -> { for (int i = 0; i < 1000; i++) { unsafeSB.append("A"); } }); Thread t2 = new Thread(() -> { for (int i = 0; i < 1000; i++) { unsafeSB.append("B"); } }); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("StringBuilder length: " + unsafeSB.length()); // Expected: 2000, Actual: might be less! (data loss) // SAFE: StringBuffer with multiple threads StringBuffer safeSB = new StringBuffer(); Thread t3 = new Thread(() -> { for (int i = 0; i < 1000; i++) { safeSB.append("A"); } }); Thread t4 = new Thread(() -> { for (int i = 0; i < 1000; i++) { safeSB.append("B"); } }); t3.start(); t4.start(); t3.join(); t4.join(); System.out.println("StringBuffer length: " + safeSB.length()); // Always: 2000 (thread-safe!) }}🛠️ Common StringBuffer Methods
StringBuffer has the SAME methods as StringBuilder!
- •
append() - Add to end - •
insert() - Add at position - •
delete() - Remove characters - •
reverse() - Flip string - •
replace() - Replace characters - •
toString() - Convert to String
📝 Usage Examples
public class StringBufferUsage { // Shared StringBuffer used by multiple threads private static StringBuffer sharedLog = new StringBuffer(); public static void main(String[] args) throws InterruptedException { // Example: Logging from multiple threads Thread logger1 = new Thread(() -> { for (int i = 0; i < 5; i++) { logMessage("Thread-1", "Message " + i); try { Thread.sleep(100); } catch (InterruptedException e) {} } }); Thread logger2 = new Thread(() -> { for (int i = 0; i < 5; i++) { logMessage("Thread-2", "Message " + i); try { Thread.sleep(100); } catch (InterruptedException e) {} } }); logger1.start(); logger2.start(); logger1.join(); logger2.join(); System.out.println("Complete log:"); System.out.println(sharedLog.toString()); } private static void logMessage(String threadName, String message) { // StringBuffer is thread-safe, so this is safe sharedLog.append("[") .append(threadName) .append("] ") .append(message) .append("\n"); }}🤔 When to Use Each?
✅ Use StringBuilder
- • Single-threaded applications (most common)
- • Local variables in methods
- • Building strings in loops
- • When performance is critical
✅ Use StringBuffer
- • Multi-threaded applications
- • Shared objects between threads
- • When thread-safety is required
- • Legacy code that requires it
⚡ Performance Comparison
public class PerformanceTest { public static void main(String[] args) { int iterations = 100000; // Test StringBuilder long start1 = System.currentTimeMillis(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < iterations; i++) { sb.append("a"); } long end1 = System.currentTimeMillis(); // Test StringBuffer long start2 = System.currentTimeMillis(); StringBuffer sbf = new StringBuffer(); for (int i = 0; i < iterations; i++) { sbf.append("a"); } long end2 = System.currentTimeMillis(); System.out.println("StringBuilder time: " + (end1 - start1) + "ms"); System.out.println("StringBuffer time: " + (end2 - start2) + "ms"); // Result: StringBuilder is faster! // StringBuilder: ~10ms // StringBuffer: ~12ms (10-20% slower due to synchronization) }}🔑 Key Concepts
Synchronized Methods
All methods are synchronized - only one thread can access at a time
public synchronized StringBuffer append(String str)Thread-Safe
Multiple threads can safely use the same StringBuffer object
Safe for concurrent modifications from different threadsPerformance Trade-off
Synchronization adds overhead, making it slower than StringBuilder
Use only when thread-safety is actually neededLegacy Class
Introduced in Java 1.0; StringBuilder added in Java 1.5 as faster alternative
For most new code, use StringBuilder instead⚠️ Common Mistakes
1. Using StringBuffer when StringBuilder would work
❌ StringBuffer sb = new StringBuffer(); // in single-threaded code
✅ StringBuilder sb = new StringBuilder(); // faster!
2. Assuming operations are atomic
❌ // Thread 1 and 2 both: if(sb.length() == 0) sb.append(x);
✅ // Use explicit synchronization for multi-step operations
3. Using for performance
❌ StringBuffer sb = new StringBuffer(); // thinking it's faster
✅ StringBuilder sb = new StringBuilder(); // this is faster!
✨ Best Practices
- ✓Use StringBuilder unless you specifically need thread-safety
- ✓Don't use StringBuffer for better performance if threads don't share the object
- ✓Consider using local variables (StringBuilder) instead of shared StringBuffer
- ✓If you need thread-safety, StringBuffer is the right choice
- ✓Remember: methods are synchronized, but sequences of operations are NOT atomic
💼 Interview Tips
- •Know the key difference: StringBuffer is synchronized, StringBuilder is not
- •Understand when to use each: single-threaded vs multi-threaded
- •Remember StringBuffer is slower due to synchronization overhead
- •Both have the same methods - only difference is thread-safety
- •StringBuffer was Java 1.0, StringBuilder added in Java 1.5
- •For new code, default to StringBuilder unless sharing between threads