【问题标题】:How does StringBuffer really work in the design of thread-safe programs? [duplicate]StringBuffer 在线程安全程序的设计中是如何真正起作用的? [复制]
【发布时间】:2014-04-20 04:02:52
【问题描述】:

很多人都提到过Java中StringBuffer和StringBuilder的区别。 StringBuffer 包含同步方法。人们会说“如果一个缓冲区被多个线程使用,请使用 StringBuffer”。但是使用 StringBuffer 真的能保证“线程安全”吗?

【问题讨论】:

  • 问和回答。这是什么??
  • @Youngistan 是的,这是允许的。
  • @Youngistan Hello.. stackoverflow 让我可以选择分享知识,问答风格。
  • 哦,我不知道这个。
  • 我已将此标记为请版主注意。提出这个问题只是为了在博客上展示答案。它更适合博客文章。它还复制其他线程。此答案可以发布到其他线程之一,并且不会丢失任何内容。

标签: java multithreading concurrency stringbuilder stringbuffer


【解决方案1】:

好吧,我认为重点介绍 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

杰里米的例子说明了这一点,我引用:

Thread 1:
sb.append("a");

Thread 2:
sb.append("b");

Thread 3:
join 1,2
print(sb.toString());

“当然,它是“线程安全的”,因为没有数据竞争(基本上是没有足够同步的并发访问)。但是你不知道线程 3 会打印什么:“ab”或“ ba"。我将不得不引入更多的同步以使其产生合理的结果。StringBuffer 附带的锁没有任何帮助。"

我希望这对你有洞察力!

【讨论】:

    猜你喜欢
    • 2014-03-18
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 2011-07-01
    • 2014-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多