Il seguente programma a volte genera eccezioni quando si utilizza StringBuilder, ma non genererà mai un'eccezione quando si utilizza StringBuffer.
Programma:
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);
}
}
};
}
Perché StringBuilder (sb
) non è thread-safe, avendo più thread scrivono i dati a sb
può provocare sb
diventare corrotti (ad esempio caratteri nulli inaspettate, le lettere di una parola inframmezzato da qualche altra parola di lettere).È anche possibile che lo stato interno sb
s' diventare abbastanza incoerente che un'eccezione può essere generata:
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)
Il seguente programma è identico al primo tranne che utilizza StringBuffer invece di StringBuilder. Non incontrerà mai 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);
}
}
};
}
Se questi programmi sono rappresentativi di un problema del "mondo reale", è una questione abbastanza soggettiva. Lascerò quel giudizio al pubblico.
fonte
2013-05-20 16:55:39
Secondo Joshua Bloch, "thread-safe" non è un tutto o niente, si assolute/nessun fenomeno. Elenca quattro categorie separate di sicurezza del thread che si distinguono principalmente per il grado in cui i client dell'API devono gestire o sincronizzare in modo proattivo. Questo è stato sviluppato da Peter Lawrey anche nella sua risposta. Nessuna classe è un'isola. – scottb