16

假设我们的应用程序只有一个线程。我们正在使用StringBuffer那么有什么问题?

我的意思是如果StringBuffer可以通过同步处理多个线程,那么使用单线程有什么问题?

为什么要StringBuilder改用?

4

8 回答 8

27

StringBuffers是线程安全的,这意味着它们具有控制访问的同步方法,因此一次只有一个线程可以访问 StringBuffer 对象的同步代码。因此,StringBuffer 对象通常可以安全地用于多线程环境中,其中多个线程可能试图同时访问同一个 StringBuffer 对象。

StringBuilder's访问不同步,因此它不是线程安全的。通过不同步,StringBuilder 的性能可以优于 StringBuffer。因此,如果您在单线程环境中工作,使用 StringBuilder 而不是 StringBuffer 可能会提高性能。这也适用于其他情况,例如只有一个线程将访问 StringBuilder 对象的 StringBuilder 局部变量(即方法中的变量)。

所以,更喜欢StringBuilder因为,

  • 性能增益小。
  • StringBuilder 是 StringBuffer 类的 1:1 替代品。
  • StringBuilder 不是线程同步的,因此在大多数 Java 实现上表现更好

看一下这个 :

于 2011-05-30T09:08:14.663 回答
7

StringBuilder 应该快一点(小),因为它不是同步的(线程安全的)。

您可以注意到真正繁重的应用程序中的差异。

通常应优先使用 StringBuilder 类,因为它支持所有相同的操作,但速度更快,因为它不执行同步。

http://download.oracle.com/javase/6/docs/api/java/lang/StringBuffer.html

于 2011-05-30T09:04:54.187 回答
5

在多个线程中使用 StringBuffer 几乎是无用的,实际上几乎不会发生。

考虑以下

Thread1: sb.append(key1).append("=").append(value1);
Thread2: sb.append(key2).append("=").append(value2);

每个追加都是同步的,但是线程可以在任何时候停止,因此您可以拥有以下任何组合以及更多

key1=value1key2=value2
key1key2==value2value1
key2key1=value1=value2
key2=key1=value2value1

这可以通过一次同步整行来避免,但这违背了使用 StringBuffer 而不是 StringBuilder 的意义。

即使您有一个正确同步的视图,它也比只创建整行的线程本地副本(例如 StringBuilder 和一次将日志行记录到 Writer 之类的类)要复杂得多。

于 2011-05-30T11:26:04.533 回答
3

StringBuffer在单线程应用程序中没有错。它的工作原理和StringBuilder.

唯一的区别是所有同步方法所增加的微小开销,这在单线程应用程序中没有任何优势。

我的观点是,引入的主要原因是编译器在编译包含连接的代码时使用和现在):在这些情况下,永远不需要同步,并且用非同步替换所有这些地方可以提供小的性能改进.StringBuilderStringBufferStringBuilderStringStringBuilder

于 2011-05-30T09:09:34.640 回答
2

StringBuilder具有更好的性能,因为它的方法不同步。

因此,如果您不需要同时构建 String (无论如何这是一个相当不典型的场景),那么就没有必要“支付”不必要的同步开销。

于 2011-05-30T09:06:33.113 回答
0

这将帮助你们,Be Straight Builder 比 Buffer 更快,

public class ConcatPerf {
        private static final int ITERATIONS = 100000;
        private static final int BUFFSIZE = 16;

        private void concatStrAdd() {
            System.out.print("concatStrAdd   -> ");
            long startTime = System.currentTimeMillis();
            String concat = new String("");
            for (int i = 0; i < ITERATIONS; i++) {
                concat += i % 10;
            }
            //System.out.println("Content: " + concat);
            long endTime = System.currentTimeMillis();
            System.out.print("length: " + concat.length());
            System.out.println(" time: " + (endTime - startTime));
        }

        private void concatStrBuff() {
            System.out.print("concatStrBuff  -> ");
            long startTime = System.currentTimeMillis();
            StringBuffer concat = new StringBuffer(BUFFSIZE);
            for (int i = 0; i < ITERATIONS; i++) {
                concat.append(i % 10);
            }
            long endTime = System.currentTimeMillis();
            //System.out.println("Content: " + concat);
            System.out.print("length: " + concat.length());
            System.out.println(" time: " + (endTime - startTime));
        }

        private void concatStrBuild() {
            System.out.print("concatStrBuild -> ");
            long startTime = System.currentTimeMillis();
            StringBuilder concat = new StringBuilder(BUFFSIZE);
            for (int i = 0; i < ITERATIONS; i++) {
                concat.append(i % 10);
            }
            long endTime = System.currentTimeMillis();
           // System.out.println("Content: " + concat);
            System.out.print("length: " + concat.length());
            System.out.println(" time: " + (endTime - startTime));
        }

        public static void main(String[] args) {
            ConcatPerf st = new ConcatPerf();
            System.out.println("Iterations: " + ITERATIONS);
            System.out.println("Buffer    : " + BUFFSIZE);

            st.concatStrBuff();
            st.concatStrBuild();
            st.concatStrAdd();
        }
    }

Output  

    run:
    Iterations: 100000
    Buffer    : 16
    concatStrBuff  -> length: 100000 time: 11
    concatStrBuild -> length: 100000 time: 4
    concatStrAdd   -> 
于 2013-02-17T17:44:49.570 回答
0

Manish,虽然只有一个线程在您的 StringBuffer 实例上运行,但在调用 StringBuffer 实例的任何方法时获取和释放该实例上的监视器锁都会产生一些开销。因此 StringBuilder 是单线程环境中的首选。

于 2013-06-05T09:58:11.667 回答
0

同步对象的成本很高。不要将程序视为独立的实体;当您阅读这些概念并将它们应用于您在问题详细信息中提到的小程序时,这不是问题,当我们想要扩展系统时会出现问题。在这种情况下,您的单线程程序可能依赖于其他几个方法/程序/实体,因此同步对象可能会在性能方面导致严重的编程复杂性。因此,如果您确定不需要同步对象,那么您应该使用 StringBuilder,因为它是一种很好的编程习惯。最后,我们想学习编程来制作可扩展的高性能系统,这就是我们应该做的!

于 2017-06-10T18:13:47.483 回答