很多人都提到了Java中StringBuffer和StringBuilder的区别。 StringBuffer包含同步方法。人们会说"如果许多线程使用缓冲区,请使用StringBuffer。"但是StringBuffer的使用是否真的能保证"线程安全"?
答案 0 :(得分:3)
嗯,我认为强调StringBuffer的一些实际用途很重要。为此,我设计了一个简单的程序来说明StringBuffer如何在实现线程安全方面优于StringBuilder。
/**
* Run this program a couple of times. We see that the StringBuilder does not
* give us reliable results because its methods are not thread-safe as compared
* to StringBuffer.
*
* For example, the single append in StringBuffer is thread-safe, i.e.
* only one thread can call append() at any time and would finish writing
* back to memory one at a time. In contrast, the append() in the StringBuilder
* class can be called concurrently by many threads, so the final size of the
* StringBuilder is sometimes less than expected.
*
*/
public class StringBufferVSStringBuilder {
public static void main(String[] args) throws InterruptedException {
int n = 10;
//*************************String Builder Test*******************************//
StringBuilder sb = new StringBuilder();
StringBuilderTest[] builderThreads = new StringBuilderTest[n];
for (int i = 0; i < n; i++) {
builderThreads[i] = new StringBuilderTest(sb);
}
for (int i = 0; i < n; i++) {
builderThreads[i].start();
}
for (int i = 0; i < n; i++) {
builderThreads[i].join();
}
System.out.println("StringBuilderTest: Expected result is 1000; got " + sb.length());
//*************************String Buffer Test*******************************//
StringBuffer sb2 = new StringBuffer();
StringBufferTest[] bufferThreads = new StringBufferTest[n];
for (int i = 0; i < n; i++) {
bufferThreads[i] = new StringBufferTest(sb2);
}
for (int i = 0; i < n; i++) {
bufferThreads[i].start();
}
for (int i = 0; i < n; i++) {
bufferThreads[i].join();
}
System.out.println("StringBufferTest: Expected result is 1000; got " + sb2.length());
}
}
// Every run would attempt to append 100 "A"s to the StringBuilder.
class StringBuilderTest extends Thread {
StringBuilder sb;
public StringBuilderTest (StringBuilder sb) {
this.sb = sb;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb.append("A");
}
}
}
//Every run would attempt to append 100 "A"s to the StringBuffer.
class StringBufferTest extends Thread {
StringBuffer sb2;
public StringBufferTest (StringBuffer sb2) {
this.sb2 = sb2;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb2.append("A");
}
}
}
然而,正如许多其他人所指出的那样, StringBuffer并不是设计线程安全应用程序的奇迹。为了更进一步,我会说用于并发的工具和库(例如Vector应该被很好地理解和适当地实现,我们不应该轻易地假设使用&#34;线程安全&#34;库。
http://jeremymanson.blogspot.sg/2008/08/dont-use-stringbuffer.html
Jeremy的例子说明了这一点,我引用:
Thread 1:
sb.append("a");
Thread 2:
sb.append("b");
Thread 3:
join 1,2
print(sb.toString());
&#34;当然,它是&#34;线程安全&#34;,在某种意义上说没有数据竞争(基本上是没有充分同步的并发访问)。但是你不知道什么线程3会打印出来:&#34; ab&#34;或&#34; ba&#34;。我将不得不引入更多的同步,以使这产生一个明智的结果。 StringBuffer附带的锁具有帮助。&#34;
我希望这对你很有见地!