问题描述
|
假设我们的应用程序只有一个线程。并且我们正在使用
StringBuffer
,这是什么问题?
我的意思是如果“ 0”可以通过同步处理多个线程,那么使用单线程有什么问题?
为什么改用StringBuilder
?
解决方法
“ 3”是线程安全的,这意味着它们具有同步方法来控制访问,因此一次只有一个线程可以访问StringBuffer对象的同步代码。因此,在多个线程可能试图同时访问同一StringBuffer对象的多线程环境中,StringBuffer对象通常是安全的。
StringBuilder\'s
访问未同步,因此不是线程安全的。通过不同步,StringBuilder的性能可以比StringBuffer更好。因此,如果您在单线程环境中工作,则使用StringBuilder代替StringBuffer可能会提高性能。在其他情况下也是如此,例如StringBuilder局部变量(即方法中的变量),其中只有一个线程将访问StringBuilder对象。
因此,更喜欢StringBuilder
,因为,
性能增益小。
StringBuilder是StringBuffer类的1:1替代品。
StringBuilder不是线程同步的,因此在大多数Java实现上表现更好
看一下这个 :
不要使用StringBuffer!
StringBuffer与StringBuilder的性能比较
, StringBuilder应该是(微小的)更快的速度,因为它不同步(线程安全)。
您会注意到真正繁重的应用程序之间的差异。
通常应优先使用StringBuilder类,因为它支持所有相同的操作,但是它更快,因为它不执行任何同步,因此它优先于该类。
http://download.oracle.com/javase/6/docs/api/java/lang/StringBuffer.html
, 在多个线程中使用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的类。
, 在单线程应用程序中,“ 0”是正确的。它会和ѭ2work一样工作。
唯一的区别是通过拥有所有同步方法而增加的微小开销,这在单线程应用程序中没有任何优势。
我认为引入introduced2ѭ的主要原因是,编译器在编译包含String
并置的代码时使用StringBuffer
(现在是StringBuilder
):在那种情况下,同步永远是没有必要的,并且可以用不同步的StringBuilder
替换所有这些位置。提供小的性能改进。
, StringBuilder
具有更好的性能,因为它的方法不同步。
因此,如果您不需要同时构建一个String(无论如何这都是非常不典型的情况),那么就不需要为不必要的同步开销“付出”。
, 这对你们有帮助
是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,因为它是一种良好的编程习惯。最后,我们想学习编程以制作可扩展的高性能系统,这就是我们应该做的!