The following program sometimes throws exceptions when using StringBuilder, but will never throw an exception when using StringBuffer.
Program:
public class StringBuilderConcurrent { static final StringBuilder sb = new StringBuilder(); // shared memory public static void main(String[] args) throws Exception { int NUM_WRITERS = 300; ArrayList<WriterThread> threads = new ArrayList<WriterThread>(NUM_WRITERS); for (int i = 0; i < NUM_WRITERS; i++) { WriterThread wt = new WriterThread("writerThread" + i); threads.add(wt); wt.start(); } for (int i = 0; i < threads.size(); i++) { threads.get(i).join(); } System.out.println(sb); } public static class WriterThread extends Thread { public WriterThread(String name) { super(name); } public void run() { String nameNl = this.getName() + "\n"; for (int i = 1; i < 20; i++) { sb.append(nameNl); } } }; }
Since StringBuilder ( sb ) is not thread safe, having multiple streams to write data to sb can damage sb (for example, unexpected null characters, word letters interspersed with some other letters). It is also possible for the internal state of sb become inconsistent enough to throw an exception:
Exception in thread "writerThread0" java.lang.ArrayIndexOutOfBoundsException at java.lang.System.arraycopy(Native Method) at java.lang.String.getChars(String.java:854) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:391) at java.lang.StringBuilder.append(StringBuilder.java:119) at test.StringBuilderConcurrent$WriterThread.run(StringBuilderConcurrent.java:35)
The following program is identical to the first, except that it uses StringBuffer instead of StringBuilder. It will never encounter an ArrayIndexOutOfBoundsException error.
public class StringBufferConcurrent { static final StringBuffer sb = new StringBuffer(); // shared memory public static void main(String[] args) throws Exception { int NUM_WRITERS = 300; ArrayList<WriterThread> threads = new ArrayList<WriterThread>(NUM_WRITERS); for (int i = 0; i < NUM_WRITERS; i++) { WriterThread wt = new WriterThread("writerThread" + i); threads.add(wt); wt.start(); } for (int i = 0; i < threads.size(); i++) { threads.get(i).join(); } System.out.println(sb); } public static class WriterThread extends Thread { public WriterThread(String name) { super(name); } public void run() { String nameNl = this.getName() + "\n"; for (int i = 1; i < 20; i++) { sb.append(nameNl); } } }; }
Whether these programs are representative of the "real world" problem is a rather subjective question. I will leave this decision to the audience.
source share