The following program will sometimes throw 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);
}
}
};
}
Because StringBuilder (sb
) is not thread safe, having multiple threads write data to sb
may result in sb
becoming corrupted (e.g. unexpected null characters, a word's letters interspersed with some other word's letters). It's also possible for sb
's internal state to become inconsistent enough that an exception might be thrown:
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 it uses StringBuffer instead of StringBuilder. It will never encounter an ArrayIndexOutOfBoundsException.
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 a "real world" problem is a fairly subjective question. I'll leave that judgement up to the audience.