关于StringBuilder与StringBuffer性能的小测试
来源:广州中睿信息技术有限公司
发布时间:2012/10/21 23:25:16 编辑:itlead 阅读 1438
  
  
  StringBuilder 是从 Java 5 以后增加的一个字符串处理类。查看 API 文档,我们可以知道 StringBuilder 和 StringBuffer 提供同样的功能,只是 StringBuilder 不保证线程安全,所以性能比 StirngBuffer 好,并推荐在确定线程安全的情况下,尽量用 StringBuilder 。事实真是如此吗?让我们通过一个小试验来看看 
  
  试验设计:
 
  分别用 StringBuilder 和 StringBuffer 将一指定的字符串自连接一百万次,比较两种方法所用的时间。为尽量避免环境的干扰,测试时会关闭本机中其它应用程序,并且为了避免测试组之间的相互干扰,在每组测试完成后会重起机器。每个程序运行十次,最后取平均值。 
  
  测试环境: 
 
  CPU: Celeron – M420 
  RAM: 1G 
  OS: Window XP Home Edition 
  JDK: Sun JDK 1.6.0 (Java HotSpot™ Client VM (build 1.6.0-b105, mixed mode, sharing)) 
  运行程序时没有为 JVM 指定任何参数,全部使用默认值 
  
  程序段:
 
  1. 用 StringBuffer 
   
  
  2. 用 StringBuilder 
   
  
  
  测试结果: 
  
   StringBuffer StringBuilder 
  1 328 328 
  2 344 312 
  3 328 328 
  4 344 312 
  5 344 328 
  6 344 312 
  7 328 328 
  8 344 312 
  9 343 328 
  10 344 328 
  平均值 339.1 321.6 
  
  从结果中可以看出两者的性能差异约为 5.44 % 
  
  下面我们将对测试程序做一点点小小的改动,在 new 一个新的 StringBuffer/StringBuilder 时,我们指定一个容量参数。修改的代码如下: 
  
  1. 用 StringBuffer 
  
   
  测试结果:(表格中第一,二组为上一轮测试的结果) 
  
   StringBuffer StringBuilder StringBuffer(int) StringBuilder(int) 
  1 328 328 140 94 
  2 344 312 125 125 
  3 328 328 125 93 
  4 344 312 125 125 
  5 344 328 109 94 
  6 344 312 125 110 
  7 328 328 125 110 
  8 344 312 110 110 
  9 343 328 140 109 
  10 344 328 109 125 
  平均值 339.1 321.6 123.3 109.5 
  
  从表中可以看到 StringBuffer(int) 和 StringBuilder(int) 两者之间的差异为 12.6% 。但我们更应该看到采用不同的构造方法所带来的性能提升, StringBuffer 提升了 175.02 %, StringBuilder 提升了 193.70% 。原因在于不指定 StirngBuffer/StringBuilder 的容量时,它们内部的字符缓冲区为 16 个字符(无参构造)或字符串参数的长度,当程序不断的进行 append/insert 操作时,每当字符数超过原有的容量后, StringBuffer/StringBuilder 将不断的进行自动扩展的工作,这将消耗比较多的时间。 
  
  也许有人会说这样的测试并不能反映真实的情况,因为在实际的开发中很少会在一个方法中构造 / 拼接一个长度为 10*1000000 的字符串的。更通常的情况是在一个方法中构造一个不太长的串,但该方法将被大量的,反复的调用。 OK, 我们可以修改一下测试程序来放映这种情况。 
  
  新程序中 contactWith…. 方法用来拼接一个不太长的字符串,该方法被 use…. 方法反复调用十万次,并记录总的调用时间。程序如下: 
 
  1. 使用 StringBuffer 
  
  
  
  2. 使用 StringBuilder 
  
  
  测试结果:
  
   StringBuffer StringBuilder StringBuffer(int) StringBuilder(int) 
  1 188 156 140 109 
  2 187 172 141 125 
  3 188 172 125 110 
  4 188 172 141 110 
  5 187 172 125 110 
  6 188 172 125 109 
  7 172 172 125 125 
  8 188 157 125 110 
  9 203 172 125 110 
  10 188 172 125 109 
  平均值 187.7 168.9 129.7 112.7 
  
  在这种情况下, StringBuffer 与 StringBuilder 的性能差别为: 11.13% 和 15.08% (使用 int 构造函数);而用不同的构造函数的性能差差异分别达到: 44.71% ( StringBuffer )和 49.87% ( StringBuilder )。并且为 StringBuffer 指定容量(使用 StirngBuffer(int) )比不指定容量的 StringBuilder 的性能高出 30.22% 。 
 
  
  结论: 
 
  1. 为了获得更好的性能,在构造 StirngBuffer 或 StirngBuilder 时应尽可能指定它的容量。当然,如果你操作的字符串长度不超过 16 个字符就不用了。 
 
  2. 相同情况下使用 StirngBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。而在现实的模块化编程中,负责某一模块的程序员不一定能清晰地判断该模块是否会放入多线程的环境中运行,因此:除非你能确定你的系统的瓶颈是在 StringBuffer 上,并且确定你的模块不会运行在多线程模式下,否则还是用 StringBuffer 吧 
 
  3. 用好现有的类比引入新的类更重要。很多程序员在使用 StringBuffer 时是不指定其容量的(至少我见到的情况是这样),如果这样的习惯带入 StringBuilder 的使用中,你将只能获得 10 %左右的性能提升(不要忘了,你可要冒多线程的风险噢);但如果你使用指定容量的 StringBuffer ,你将马上获得 45% 左右的性能提升,甚至比不使用指定容量的 StirngBuilder 都快 30% 左右。 
 
  
  特别声明:
 
  1 .本人是基于 Window XP 环境,用 Sun 的 JDK 1.6 完成的以上测试。测试的结果是否能反映其它操作系统(如 Linux, Unix 等)和不同的 JDK (IBM, Weblogic 等 ) 的情况就不得而知,有兴趣的网友可以在不同的环境中测试,欢迎您告诉我测试结果。 
  
 

 本站技术原创栏目文章均为中睿原创或编译,转载请注明:文章来自中睿,本站保留追究责任的权利。