本文介绍了String、StringBuffer 和 StringBuilder 之间的性能和简单性权衡的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您有没有想过这种变化对 Java 编程语言的影响?

Have you ever thought about the implications of this change in the Java Programming Language?

String 类被认为是一个不可变的类(这个决定是经过深思熟虑的).但是字符串连接真的很慢,我自己对它进行了基准测试.于是 StringBuffer 诞生了.非常棒的课程,同步且非常快.但是有些人对一些同步块的性能成本并不满意,于是引入了 StringBuilder.

The String class was conceived as an immutable class (and this decision was intentionally thought-out). But String concatenation is really slow, I've benchmarked it myself. So the StringBuffer was born. Really great class, synchronized and really fast. But some people were not happy with the performance cost of some synchronized blocks, and the StringBuilder was introduced.

但是,当使用 String 连接的对象不多时,类的不变性使其成为实现线程安全的一种非常自然的方式.当我们要管理多个String时,我可以理解StringBuffer的使用.但是,这是我的第一个问题:

But, when using String to concatenate not too many objects, the immutability of the class makes it a really natural way to achieve thread-safety. I can understand the use of StringBuffer when we want to manage several Strings. But, here is my first question:

  1. 例如,如果您有 10 个或更少的字符串要附加,您是否会在执行时间上只牺牲几毫秒的简单性?

我也对 StringBuilder 进行了基准测试.它比 StringBuffer 更有效(仅提高 10%).但是,如果在您的单线程程序中使用 StringBuilder,如果您有时想要更改设计以使用多个线程,会发生什么情况?您必须更改 StringBuilder 的每个实例,如果您忘记了一个实例,则会产生一些奇怪的效果(考虑到可能出现的竞争条件).

I've benchmarked StringBuilder too. It is more efficient than StringBuffer (just a 10% improvement). But, if in your single-threaded program you're using StringBuilder, what happens if you sometimes want to change the design to use several threads? You have to change every instance of StringBuilder, and if you forget one, you'll have some weird effect (given the race condition that may arise) that can be produced.

在这种情况下,你会用性能换取几个小时的调试时间吗?

好的,就这些.除了这个简单的问题(StringBuffer 比+"和线程安全更有效,StringBuilder 比 StringBuffer 快但没有线程安全)我想知道什么时候使用它们.

Ok, that's all. Beyond the simple question (StringBuffer is more efficient than "+" and thread-safe, and StringBuilder is faster than StringBuffer but no thread-safe) I would like to know when to use them.

(重要:我知道它们之间的区别;这是一个与平台架构和一些设计决策相关的问题.)

(Important: I know the differences between them; this is a question related to the architecture of the platform and some design decisions.)

推荐答案

现在 StringBuffer 和 Builder 都没什么用(从性能的角度来看).我解释一下原因:

Nowadays both StringBuffer and Builder are sort of useless (from performance point of view).I explain why:

StringBuilder 应该比 StringBuffer 更快,但任何正常的 JVM 都可以优化同步.因此,当它被引入时,它是一个非常大的失误(而且影响很小).

StringBuilder was supposed to be faster than StringBuffer but any sane JVM can optimize away the synchronization. So it was quite a huge miss (and small hit) when it was introduced.

StringBuffer 在创建 String 时不用于复制 char[](在非共享变体中);然而,这是问题的一个主要来源,包括为小字符串泄漏巨大的 char[].在 1.5 中,他们决定每次都必须出现 char[] 的副本,这实际上使 StringBuffer 变得无用(同步是为了确保没有线程游戏可以欺骗 String).这节省了内存,但最终有助于 GC(除了明显减少的占用空间),通常 char[] 是消耗内存的对象的前 3 个.

StringBuffer used NOT to copy the char[] when creating the String (in non shared variant); however that was a major source of issues, incl leaking huge char[] for small Strings. In 1.5 they decided that a copy of the char[] must occur every time and that practically made StringBuffer useless (the sync was there to ensure no thread games can trick out the String). That conserves memory, though and ultimately helps the GC (beside the obviously reduced footprint), usually the char[] is the top3 of the objects consuming memory.

String.concat 过去和现在仍然是连接 2 个字符串(并且只有 2 个……或者可能是 3 个)的最快方法.请记住,它不会执行 char[] 的额外副本.

String.concat was and still is the fastest way to concatenate 2 strings (and 2 only... or possibly 3). Keep that in mind, it does not perform an extra copy of the char[].

回到没用的部分,现在任何 3rd 方代码都可以达到与 StringBuilder 相同的性能.即使在 java1.1 中,我曾经有一个类名 AsycnStringBuffer,它与 StringBuilder 现在所做的完全相同,但它仍然分配了比 StringBuilder 更大的 char[].默认情况下,StrinBuffer/StringBuilder 都针对小字符串进行了优化,您可以看到 c-tor

Back to the useless part, now any 3rd party code can achieve the same performance as StringBuilder. Even in java1.1 I used to have a class name AsycnStringBuffer which did exactly the same what StringBuilder does now, but still it allocates larger char[] than StringBuilder. Both StrinBuffer/StringBuilder are optimized for small Strings by default you can see the c-tor

  StringBuilder(String str) {
    super(str.length() + 16);
    append(str);
    }

因此,如果第二个字符串的长度超过 16 个字符,则它会获得底层的另一个副本字符[].很不爽.

Thus if the 2nd string is longer than 16chars, it gets another copy of the underlying char[]. Pretty uncool.

这可能是在 32 位操作系统上尝试将 StringBuilder/Buffer 和 char[] 放入同一缓存行(在 x86 上)的副作用......但我不确定.

That can be a side effect of attempt at fitting both StringBuilder/Buffer and the char[] into the same cache line (on x86) on 32bit OS... but I don't know for sure.

至于调试时间的评论等.根据您的判断,我个人不记得有任何字符串操作问题,除了 impl.JDO impl sql 生成器的类似rope 结构

As for the remark of hours of debugging, etc. Use your judgment, I personally do not recall ever having any issues w/ strings operations, aside impl. rope alike structure for the sql generator of JDO impl.

下面我将说明 java 设计者没有做些什么来使 String 操作更快.请注意,该类是为 java.lang 包设计的,它只能通过将它添加到引导类路径来放置.但是,即使不放在那里(不同的是一行代码!),它仍然比StringBuilder快,令人震惊?该类会使 string1+string2+... 比使用 StringBuilder 好很多,但好吧...

Below I illustrate what java designers didn't do to make String operations faster.Please, note that the class is intended for java.lang package and it can put there only by adding it to the bootstrap classpath. However, even if not put there (the difference is a single line of code!), it'd be still faster than StringBuilder, shocking? The class would have made string1+string2+... a lot better than using StringBuilder, but well...

package java.lang;

public class FastConcat {

    public static String concat(String s1, String s2){
        s1=String.valueOf(s1);//null checks
        s2=String.valueOf(s2);

        return s1.concat(s2);
    }

    public static String concat(String s1, String s2, String s3){
        s1=String.valueOf(s1);//null checks
        s2=String.valueOf(s2);
        s3=String.valueOf(s3);
        int len = s1.length()+s2.length()+s3.length();
        char[] c = new char[len];
        int idx=0;
        idx = copy(s1, c, idx);
        idx = copy(s2, c, idx);
        idx = copy(s3, c, idx);
        return newString(c);
    }
    public static String concat(String s1, String s2, String s3, String s4){
        s1=String.valueOf(s1);//null checks
        s2=String.valueOf(s2);
        s3=String.valueOf(s3);
        s4=String.valueOf(s4);

        int len = s1.length()+s2.length()+s3.length()+s4.length();
        char[] c = new char[len];
        int idx=0;
        idx = copy(s1, c, idx);
        idx = copy(s2, c, idx);
        idx = copy(s3, c, idx);
        idx = copy(s4, c, idx);
        return newString(c);

    }
    private static int copy(String s, char[] c, int idx){
        s.getChars(c, idx);
        return idx+s.length();

    }
    private static String newString(char[] c){
        return new String(0, c.length, c);
        //return String.copyValueOf(c);//if not in java.lang
    }
}

这篇关于String、StringBuffer 和 StringBuilder 之间的性能和简单性权衡的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-27 18:18