StringBuilder 误解:

1. Java编译优化后+和StringBuilder的效果一样;

2. StringBuilder不是线程安全的,为了“安全”起见最好还是用StringBuffer;

3. 永远不要自己拼接日志信息的字符串,交给slf4j来。

初始长度好重要,值得说四次。

StringBuilder的内部有一个char[], 不断的append()就是不断的往char[]里填东西的过程。

new StringBuilder() 时char[]的默认长度是16,然后,如果要append第17个字符,怎么办?

用System.arraycopy成倍复制扩容!!!!

这样一来有数组拷贝的成本,二来原来的char[]也白白浪费了要被GC掉。可以想见,一个129字符长度的字符串,经过了16,32,64, 128四次的复制和丢弃,合共申请了496字符的数组,在高性能场景下,这几乎不能忍。

所以,合理设置一个初始值多重要。

但如果我实在估算不好呢?多估一点点好了,只要字符串最后大于16,就算浪费一点点,也比成倍的扩容好。

Liferay的StringBundler类

Liferay的StringBundler类提供了另一个长度设置的思路,它在append()的时候,不急着往char[]里塞东西,而是先拿一个String[]把它们都存起来,到了最后才把所有String的length加起来,构造一个合理长度的StringBuilder。

但,还是浪费了一倍的char[]

浪费发生在最后一步,StringBuilder.toString()

// Create a copy, don't share the array
return new String(value, 0, count);

String的构造函数会用 System.arraycopy()复制一把传入的char[]来保证安全性不可变性,如果故事就这样结束,StringBuilder里的char[]还是被白白牺牲了。

为了不浪费这些char[],一种方法是用Unsafe之类的各种黑科技,绕过构造函数直接给String的char[]和count属性赋值,但很少人这样做。

另一个靠谱一些的办法就是重用StringBuilder。而重用,还解决了前面的长度设置问题,因为即使一开始估算不准,多扩容几次之后也够了。

重用StringBuilder

这个做法来源于JDK里的BigDecimal类(没事看看JDK代码多重要),SpringSide里将代码提取成StringBuilderHolder,里面只有一个函数

public StringBuilder getStringBuilder() {
sb.setLength(0);
return sb;
}

StringBuilder.setLength()函数只重置它的count指针,而char[]则会继续重用,而toString()时会把当前的count指针也作为参数传给String的构造函数,所以不用担心把超过新内容大小的旧内容也传进去了。可见,StringBuilder是完全可以被重用的。

为了避免并发冲突,这个Holder一般设为ThreadLocal,标准写法见BigDecimal或StringBuilderHolder的注释

+ 与 StringBuilder

String s = “hello ” + user.getName();

这一句经过javac编译后的效果,的确等价于使用StringBuilder,但没有设定长度。

String s = new StringBuilder().append(“hello”).append(user.getName());

但是,如果像下面这样:

String s = “hello ”;
// 隔了其他一些语句
s = s + user.getName();

每一条语句,都会生成一个新的StringBuilder,这里就有了两个StringBuilder,性能就完全不一样了。如果是在循环体里s+=i; 就更加多得没谱。

据R大说,努力的JVM工程师们在运行优化阶段, 根据+XX:+OptimizeStringConcat(JDK7u40后默认打开),把相邻的(中间没隔着控制语句) StringBuilder合成一个,也会努力的猜长度。

所以,保险起见还是继续自己用StringBuilder并设定长度好了。

StringBuffer 与 StringBuilder

StringBuffer与StringBuilder都是继承于AbstractStringBuilder,唯一的区别就是StringBuffer的函数上都有synchronized关键字

那些说StringBuffer “安全”的同学,其实你几时看过几个线程轮流append一个StringBuffer的情况???

永远把日志的字符串拼接交给slf4j??

logger.info("Hello {}", user.getName());

对于不知道要不要输出的日志,交给slf4j在真的需要输出时才去拼接的确能省节约成本。

但对于一定要输出的日志,直接自己用StringBuilder拼接更快。因为看看slf4j的实现,实际上就是不断的indexof("{}"), 不断的subString(),再不断的用StringBuilder拼起来而已,没有银弹。

PS. slf4j中的StringBuilder在原始Message之外预留了50个字符,如果可变参数加起来长过50字符还是得复制扩容......而且StringBuilder也没有重用。

小结

StringBuilder默认的写法,会为129长度的字符串拼接,合共申请625字符的数组。所以高性能的场景下,永远要考虑用一个ThreadLocal 可重用的StringBuilder。而且重用之后,就不用再玩猜长度的游戏了。

Java StringBuilder 高性能用法总结的更多相关文章

  1. java中stringBuilder的用法

    java中stringBuilder的用法 String对象是不可改变的.每次使用 System.String类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为该新对象分配新的空间.在需 ...

  2. JAVA的continue用法

    JAVA的continue用法: public class test{ public static void main(String [] args){  for(int i=0;i<=10;i ...

  3. Java Spring AOP用法

    Java Spring AOP用法 Spring AOP Java web 环境搭建 Java web 项目搭建 Java Spring IOC用法 spring提供了两个核心功能,一个是IoC(控制 ...

  4. Java Spring IOC用法

    Java Spring IOC用法 Spring IoC 在前两篇文章中,我们讲了java web环境搭建 和 java web项目搭建,现在看下spring ioc在java中的运用,开发工具为In ...

  5. 四种Java线程池用法解析

    本文为大家分析四种Java线程池用法,供大家参考,具体内容如下 http://www.jb51.net/article/81843.htm 1.new Thread的弊端 执行一个异步任务你还只是如下 ...

  6. JAVA中ArrayList用法

    JAVA中ArrayList用法 2011-07-20 15:02:03|  分类: 计算机专业 |  标签:java  arraylist用法  |举报|字号 订阅     Java学习过程中做题时 ...

  7. Java Web高性能开发(三)

    今日要闻: Clarifai:可识别视频中物体 最近几年,得益于深度学习技术的发展,谷歌和Facebook等企业的研究人员在图形识别软件领域取得了重大突破.现在,一家名为Clarifai的创业公司则提 ...

  8. Java Web高性能开发(二)

    今日要闻: 性价比是个骗局: 对某个产品学上三五天个把月,然后就要花最少的钱买最多最好的东西占最大的便宜. 感谢万能的互联网,他顺利得手,顺便享受了智商上的无上满足以及居高临下的优越感--你们一千块买 ...

  9. Java Web 高性能开发,第 3 部分: 网站优化实战

    这个系列的前两篇,介绍了前端的优化技术,这些技术秉承了前人至高无上的智慧,我只是负责吸收和传播.然而,这些技术一般也都是某某大型网站的技术经验,我们大部分人或许只能接触到相对小规模的网站,小规模的网站 ...

随机推荐

  1. iOS学习11之OC继承

    面向对象的三大特性:封装,继承,多态. 1.继承 继承既能保证类的完整,又能简化代码. 把公共的⽅法和实例变量写在⽗类⾥,⼦类只需要写⾃⼰独有的实例变量和⽅法即可. 继承是⾯向对象三⼤特性之⼀,合理的 ...

  2. BZOJ3588 : fx

    考虑从左往右填数,维护当前数字权值与$A$权值的差值,如果差值大于9,那么以后无论怎么填,都不会改变大小关系. 所以设$f[i][j][k]$表示填了前$i$位,差值为$j$,是否卡住$B$上限为$k ...

  3. angularjs 实现 文件拖拽,缩略图显示

    成果图: main-hugeScreen.html <div class="hbox hbox-auto-xs hbox-auto-sm" ng-controller=&qu ...

  4. Java的集合类

    转自:Q.Mr的博客 http://www.cnblogs.com/zrtqsk/p/3472258.html (本人第一次写博客,部分内容有参照李刚老师的疯狂java系列图书,如有遗漏错误,请多指教 ...

  5. hdu 1312 Red and Black

    Problem Description There is a rectangular room, covered with square tiles. Each tile is colored eit ...

  6. background-attachment 定义背景图片随滚动轴的移动方式

  7. 警惕自己,不断学习c++【转】

    每天早上起床看一遍,时刻警惕自己,每天至少要浏览http://www.cplusplus.com 1.把C++当成一门新的语言学习(和C没啥关系!真的.):2.看<Thinking In C++ ...

  8. tshark (wireshark)笔记

    1. dumpcap -i eth0 -q -n -b duration:120 -b files:5000 -s65535 -f "! ip broadcast and ! ip mult ...

  9. Hashtable在ViewState中无法增加值

    在我调试程序的时候,我发现WebForm 2.0和MVC3解析ViewState的方式不同,同样的代码,在Weorm中管用,在MVC中不起作用. private Hashtable ht { get ...

  10. PS中常用快捷键

    Prtsc:印屏幕 Tab:隐藏工具栏 F:图片在编辑区的显示模式 F8:显示选中框区域的信息 Ctrl+N:新建画布 Ctrl+'+':放大 Ctrl+'-':缩小 工具栏三角形+鼠标:拖拽(只移动 ...