一入侯门深似海,大家两年不见了。

1. 开场白

这次复活的是SpringSide-Utils模块,把在唯品会两年的实践抽取出来,做一个大大大的公共类库。一边封装 Guava 和 Apache Common Lang,一边参考移植各门各派的精华:


大家可能都忘了,再贴一次门牌:https://git.oschina.net/calvin1978/springside4 

希望大家继续发挥点赞党的优良传统,在码云里顺手点个 “Star”

内库中包含了文本、数字、日期、并发、集合、文件、反射、安全等方面的内容等着大家一一探索,这里又再唠叨一下性能,性能,性能。

新库的设计目标,是把最佳实践都封装起来,让大家使用类库时,默认就获得最优的性能。



2. 日期

2.1 DateFormatUtil

日期与String相互转换时,JDK的SimpleDateFormat,又慢,又非线程安全。

在不能全面转为Joda Time时,使用Common Lang的FastDateFormat,又快,又线程安全,还能缓存实例。

2.2 CachingDateFormatter

FastDateFormat再快,日期格式化还是个消耗很大的事情。

参考Logback和Log4j2,在打印当前时间的场景里,将同一时刻的结果缓存。


3. 文本

3.1 StringBuilderHolder

ThreadLocal地重用StringBuilder,节约长字符串拼接时的内存消耗,节约成倍复制扩容的CPU消耗,是OpenHFT等好几个类库的共同选择。

3.2 HashUtil

ThreadLocal地重用SHA1的MessageDiggest,减少每次创建MessageDigest的消耗,也是Tomcat,Facebook等好几个类库的共同选择。

3.3 JsonMapper

封装Jackson的实现,并提供不序列化“值为NULL的属性”等选择。

3.4 TextValidator

判断是否合法的电话,身份证之类的正则表达式校验,Pattern必须得预先编译而不要每次创建,但总有匆忙的同学忘记这点。

3.5 MoreStringUtil

Common Lang的StringUtils已经很好用了。不过字符串操作的消耗总是很大,这里针对一些操作,给出更极致的性能优化,比如split()。


4. 集合


4.1 原子类型集合

当集合中的元素是原子类型,而不是对象的时候。直接以原子类型来存储,不但节约内存(int vs Integer, 4 bytes vs 16 bytes),甚至内部的数据结构也能完全不一样,从而大幅提高性能。

从Netty中移植了IntOjbectHashMap 和 LongObjectHashMap,性能约提升50%。后面还会有IntArrayList等等。

4.2  MapUtil, ListUtil ...

各种集合类的Util的创建函数,强迫大家去思考Array Base 集合类的初始大小,避免了容量不足时的成倍扩容; HashMap的加载因子,减少哈希冲突。

在集合为空或只有一个元素时,使用Java Collections的特殊数据结构,进一步节约内存。

4.3 其他扩展类型

1. Guava

2. Common Collections

3. Jodd

4. JCTools

 

5. 并发

5.1 JSR166e

JDK的不同版本,不断推出性能更优的并发实现,但如果考虑多JDK版本到的兼容就让人发愁了。好在有Doug Lea大神的JSR166e项目。

1. ThreadLocalRandom

Random本身有全局锁,JDK7的ThreadLocalRandom通过在ThreadLocal里放Random避免了锁。

2. LongAdder

作为计数器,AtomicLong虽然能通过CAS避免锁,但如果线程竞争激烈时依然有很大的损耗。JDK8的LongAdder,根据并发情况,将计数器智能的拆开成若干个,等取值时再求和。

3. ConcurrentHashMapV8

JDK5开始的ConcurrentHashMap是经典的分散锁模式,而JDK8的ConcurrentHashMap,优化后居然取消了锁。

5.2 ThreadPoolBuilder

比JDK Executors,提供更好的线程池设置,比如FixedPool的队列最大长度,CachedPool的最大线程数等。

另提供一个从Tomcat移植的QueueableCachedPool,“支持可变的线程数,跑满线程时任务放队列”这种符合大家想想的场景。

5.3 ThreadLocalContext

提供ThreadLocal HashMap存放上下文的示例,并给出更高效的,使用EnumMap的建议。


6. 反射

6.1 BeanMapper

基于orika封装,同时避免了一些低效API的使用,比如不给出来源集合的类型,让框架自己去反射"iterator"函数的返回值来获取类型的恶劣行为。

更给出了预生成Type类型的最高效的用法。

6.2 FastMethodInvoker

基于cglib,通过代码生成实现最快速的反射调用。比如反射调用A类的“hello” 方法,它就直接生成一个调用a.hello()的FastMethod子类.

7. 其他

7.1 ExceptionUtil

异常构造时,获取当前Stack Trace是一个很耗时的过程,把Stack Trace打印也同样消耗。

如果是一个比较清楚出处的异常,可以通过static定义的静态异常。

但如果异常的message会变化,就不能静态定义唯一的异常了,此时可使用克隆异常,依然避过构造函数。

7.2 SystemPropertiesUtil

Properties本质上是一个有锁的HashTable,所以不能频繁的调用System.getProperty()。提供了一个以回调方式获取变化的ListenableProperties。


一切皆是开始,每天仍在添砖。

希望大家在码云里继续点赞党的天赋气质,顺手点个 “Star”。

https://git.oschina.net/calvin1978/springside4



新闻来源:好久不见,SpringSide 归来,有性能的基础库