【发布时间】:2011-09-04 16:18:49
【问题描述】:
假设我们的应用程序只有一个线程。而我们使用的是StringBuffer,那么有什么问题呢?
我的意思是如果StringBuffer 可以通过同步处理多个线程,那么使用单线程有什么问题?
为什么要改用StringBuilder?
【问题讨论】:
标签: java multithreading synchronization stringbuilder stringbuffer
假设我们的应用程序只有一个线程。而我们使用的是StringBuffer,那么有什么问题呢?
我的意思是如果StringBuffer 可以通过同步处理多个线程,那么使用单线程有什么问题?
为什么要改用StringBuilder?
【问题讨论】:
标签: java multithreading synchronization stringbuilder stringbuffer
StringBuilder 应该快一点(小),因为它不是同步的(线程安全的)。
您会注意到在真正繁重的应用程序中的差异。
通常应优先使用 StringBuilder 类,因为它支持所有相同的操作,但速度更快,因为它不执行同步。
http://download.oracle.com/javase/6/docs/api/java/lang/StringBuffer.html
【讨论】:
Why use StringBuilder instead? - 答案:StringBuilder is supposed to be a (tiny) bit faster(这篇文章的第一句话)
StringBuilder 具有更好的性能,因为它的方法是不同步的。
因此,如果您不需要同时构建字符串(无论如何这是一个相当不典型的场景),则无需“支付”不必要的同步开销。
【讨论】:
StringBuffers 是线程安全的,这意味着它们具有控制访问的同步方法,因此一次只有一个线程可以访问 StringBuffer 对象的同步代码。因此,StringBuffer 对象通常可以安全地用于多线程环境中,其中多个线程可能试图同时访问同一个 StringBuffer 对象。
StringBuilder's 访问不同步,因此它不是线程安全的。通过不同步,StringBuilder 的性能可以优于 StringBuffer。因此,如果您在单线程环境中工作,使用 StringBuilder 而不是 StringBuffer 可能会提高性能。这也适用于其他情况,例如只有一个线程将访问 StringBuilder 对象的 StringBuilder 局部变量(即方法中的变量)。
所以,更喜欢StringBuilder,因为,
看看这个:
【讨论】:
StringBuilder 并不是 StringBuffer 的 1:1 替代品。例如,Matcher 的 appendReplacement 方法需要 StringBuffer 作为其第一个参数。
StringBuffer 在单线程应用程序中没有错误。它和StringBuilder 一样好用。
唯一的区别是所有同步方法所增加的微小开销,这在单线程应用程序中没有任何优势。
我认为引入StringBuilder 的主要 原因是编译器在编译包含String 连接的代码时使用StringBuffer(现在是StringBuilder):在那些案例同步从不是必要的,将所有这些地方替换为未同步的StringBuilder 可以提供小的性能改进。
【讨论】:
在多个线程中使用 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 之类的类中。
【讨论】:
这将帮助你们, 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 ->
【讨论】:
Manish,虽然只有一个线程在您的 StringBuffer 实例上运行,但在调用 StringBuffer 实例的任何方法时,在获取和释放该实例上的监视器锁时都会产生一些开销。因此 StringBuilder 是单线程环境下的首选。
【讨论】:
同步对象的成本很高。不要将程序视为独立的实体;当您阅读这些概念并将它们应用于您在问题详细信息中提到的小程序时,这不是问题,当我们想要扩展系统时会出现问题。在这种情况下,您的单线程程序可能依赖于其他几个方法/程序/实体,因此同步对象可能会在性能方面导致严重的编程复杂性。因此,如果您确定不需要同步对象,那么您应该使用 StringBuilder,因为它是一种很好的编程习惯。最后我们想学习编程来制作可扩展的高性能系统,这就是我们应该做的!
【讨论】: