红联Linux门户
Linux帮助

好久不见,SpringSide归来,有性能的基础库

发布时间:2017-01-16 23:19:26来源:红联作者:uineqa
一入侯门深似海,大家两年不见了。

1. 开场白

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

框架/容器随身自带:Spring,Netty,Tomcat,Jetty,ElasticSearch

专门的类库:Jodd, Apache Common IO,Common Collections,JCTool,OpenHFT,AndroidUtilCode

大厂的开源类库:Facebook JCommon,twitter commons,linkedin-utils

大家可能都忘了,再贴一次门牌: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

MuitlSet :as MapCounter,不用再自己处理“如果有就+1,没有就放个元素进去”的烦事

MultiMap: as MultiValueMap

WeakConcurrentHashMap: 键值为弱引用的并发Map,只此一家

RangeMap:定义一段范围的Key,对应一个Value,类似一致性哈希环之类的最合适

2. Common Collections:

UniqueArrayList

MultiKeyMap

Flat3Map:如果少于3个元素直接访问属性,否则才访问真正的HashMap

3. Jodd

SortedArrayList

4. JCTools

针对 “多个生产者一个消费者”, “一个生产者多个消费者” 等特定场景优化的Queue。

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。

软件详情:https://github.com/springside/springside4

下载地址:http://git.oschina.net/calvin1978/springside4

来自:开源中国社区
文章评论

共有 0 条评论