性能测试工具
- ab(ApacheBench),在 linux 中使用,直接使用
yum-y install httpd-tools
安装即可。 - JMeter,在Windows系统中有图形界面。
编码优化
字符串优化
1.构建超大字符串时,注意显示引用 StringBuilder|StringBuffer
,而不要使用 + 进行拼接。
2.合理使用 String.intern()
,可以使重复性非常高的字符串(例如地址信息存储),重复使用常量池中相同值的对象,进而节约内存。
动态字符串创建后,是在堆中,值相同的不同String对象,它们指向不同的地址。 而
String.intern()
会让堆中的字符串先存在字符串常量池,再让引用指向同一个常量池的地址。
使用
String.intern()
方法需要注意的一点是,一定要结合实际场景。因为常量池的实现是类似于一个HashTable的实现方式,HashTable存储的数据越大,遍历的时间复杂度就会增加。如果数据过大,会增加整个字符串常量池的负担。
3.慎用split()
方法,因为split()
方法使用了正则表达式,而正则表达式的性能是非常不稳定的,使用不恰当会引起回溯问题,很可能导致CPU居高不下。
慎用正则表达式。 必须使用的情况下需要注意正则表达式的优化。
- 少用贪婪模式,多用独占模式。(在字符后面加一个“
+
”,就可以开启独占模式)
- 同贪婪模式一样,独占模式一样会最大限度地匹配更多内容;不同的是,在独占模式下,匹配失败就会结束匹配,不会发生回溯问题。
- 减少分支选择。分支选择类型“(X|Y|Z)”的正则表达式会降低性能。如果一定要用,可以通过以下几种方式来优化
- 首先,考虑选择分支顺序,将比较常用的选择项放在前面,使它们可以较快地被匹配;
- 其次,尝试提取共用模式,例如,将“
(abcd|abef)
”替换为“ab(cd|ef)
”,后者匹配速度较快;- 最后,如果是简单的分支选择类型,我们可以用三次
indexOf()
代替“(X|Y|Z)
”。- 减少捕获嵌套
- 另外,如果你并不需要获取某一个分组内的文本,那么就使用非捕获分组。例如,使用“(?:X)”代替“(X)”。
ArrayList 和 LinkedList
在我们的认知中 ,ArrayList
和LinkedList
在新增、删除元素时,LinkedList
的效率要高于 ArrayList
,而在遍历的时候,ArrayList
的效率要高于LinkedList
。
ArrayList和LinkedList新增元素
- 从集合头部位置新增元素
ArrayList
是数组实现的,在添加元素前,需要对头部后的数据进行复制,所以效率很低;LinkedList
是基于链表实现,在添加元素前,首先会通过循环查找到添加元素的位置,直接新增不需要进行复制。LinkedList
添加元素到头部是非常高效的。
- 从集合中间位置新增元素
ArrayList
在添加元素到数组中间时,同样有部分数据需要复制,效率也不高;LinkedList
将元素添加到中间位置,是添加元素最低效率的,因为靠近中间位置,在添加元素之前的循环查找是遍历元素最多的操作。
- 从集合尾部位置新增元素
- 添加元素到尾部的操作中,在没有扩容的情况下,
ArrayList
的效率要高于LinkedList
。 - 这是因为
ArrayList
在添加元素到尾部的时候,不需要复制重排数据,效率非常高。 LinkedList
虽然也不用循环查找元素,但LinkedList
中多了new
对象以及变换指针指向对象的过程,所以效率要低于ArrayList
。
- 添加元素到尾部的操作中,在没有扩容的情况下,
ArrayList和LinkedList删除元素
- 从集合头部位置删除元素
- 从集合中间位置删除元素
- 从集合尾部位置删除元素
ArrayList
和LinkedList
的删除的过程与新增过程的原理一样。
ArrayList和LinkedList遍历元素
for(;;)
循环LinkedList
的for循环
性能是最差的,而ArrayList
的for循环
性能是最好的。
- 迭代器迭代循环
LinkedList
的迭代循环遍历和ArrayList
的迭代循环遍历性能相当,也不会太差,所以在遍历LinkedList
时,要切忌使用for循环遍历。
合理使用Stream
- 在循环迭代次数较少的情况下,常规的迭代方式性能反而更好;
- 在单核CPU服务器配置环境中,也是常规迭代方式更有优势;
- 而在大数据循环迭代中,如果服务器是多核CPU的情况下,Stream的并行迭代优势明显。
我们在平时处理大数据的集合时,应该尽量考虑将应用部署在多核CPU环境下,并且使用Stream的并行迭代方式进行处理。
HashMap
在使用HashMap
时,可以结合自己的场景来设置初始容量和加载因子两个参数。
- 当查询操作较为频繁时,我们可以适当地减少加载因子;
- 如果对内存利用率要求比较高,我可以适当的增加加载因子。
我们还可以在预知存储数据量的情况下,提前设置初始容量(初始容量=预知数据量/加载因子
)。这样做的好处是可以减少 resize() 操作,提高HashMap
的效率。