Chương trình sau đây đôi khi sẽ ném ngoại lệ khi sử dụng StringBuilder, nhưng sẽ không bao giờ ném ngoại lệ khi sử dụng StringBuffer.
Chương trình:
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);
}
}
};
}
Bởi vì StringBuilder (sb
) không phải là thread an toàn, có nhiều đề ghi dữ liệu vào sb
có thể dẫn đến sb
trở thành bị hỏng (ví dụ ký tự null bất ngờ, chữ của một từ xen kẽ với một số từ của người khác bức thư).Nó cũng có thể cho trạng thái nội sb
's để trở thành đủ không phù hợp mà một ngoại lệ có thể được ném:
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)
Các chương trình sau đây là giống hệt nhau để là người đầu tiên ngoại trừ nó sử dụng StringBuffer thay vì StringBuilder. Nó sẽ không bao giờ gặp phải một 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);
}
}
};
}
Cho dù các chương trình này đại diện cho một vấn đề "thực tế" là một câu hỏi khá chủ quan. Tôi sẽ để lại sự phán xét đó cho khán giả.
Nguồn
2013-05-20 16:55:39
Theo Joshua Bloch, "thread safe" không phải là một hiện tượng hoàn toàn có/không có. Ông liệt kê 4 loại an toàn chủ đề riêng biệt được phân biệt chủ yếu bởi mức độ mà khách hàng của API phải chủ động quản lý hoặc đồng bộ hóa. Điều này được phát triển bởi Peter Lawrey trong phản ứng của ông là tốt. Không có lớp nào là một hòn đảo. – scottb