StringBuffer在设计线程安全程序中真正起到了什么作用?
StringBuffer在设计线程安全程序中真正起到了什么作用?
这个问题已经有答案了:
许多人提到了Java中StringBuffer和StringBuilder之间的区别。StringBuffer包含同步方法。人们说:“如果一个缓冲区被多个线程使用,请使用StringBuffer。”但是,使用StringBuffer真的能保证“线程安全”吗?
admin 更改状态以发布 2023年5月24日
我认为强调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)应该得到充分理解和适当实现,我们不应该轻易地假设使用“线程安全”的库。
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());
"当然,它是“线程安全”的,因为没有数据竞争(基本上是没有足够同步的并发访问)。但你不知道线程3将打印什么:“ab”还是“ba” 。我必须引入更多的同步来使其产生一个合理的结果。StringBuffer带来的锁并没有起到任何作用。"
希望这对你有启示!