Java性能调优 - 编码优化

发布于:2024-12-18 ⋅ 阅读:(75) ⋅ 点赞:(0)

在这里插入图片描述

性能测试工具

  • 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居高不下。

慎用正则表达式。 必须使用的情况下需要注意正则表达式的优化。

  1. 少用贪婪模式,多用独占模式。(在字符后面加一个“+”,就可以开启独占模式)
    • 同贪婪模式一样,独占模式一样会最大限度地匹配更多内容;不同的是,在独占模式下,匹配失败就会结束匹配,不会发生回溯问题。
  2. 减少分支选择。分支选择类型“(X|Y|Z)”的正则表达式会降低性能。如果一定要用,可以通过以下几种方式来优化
    • 首先,考虑选择分支顺序,将比较常用的选择项放在前面,使它们可以较快地被匹配;
    • 其次,尝试提取共用模式,例如,将“(abcd|abef)”替换为“ab(cd|ef)”,后者匹配速度较快;
    • 最后,如果是简单的分支选择类型,我们可以用三次indexOf()代替“(X|Y|Z)”。
  3. 减少捕获嵌套
    • 另外,如果你并不需要获取某一个分组内的文本,那么就使用非捕获分组。例如,使用“(?:X)”代替“(X)”。

ArrayList 和 LinkedList

在我们的认知中 ,ArrayListLinkedList在新增、删除元素时,LinkedList的效率要高于 ArrayList,而在遍历的时候,ArrayList的效率要高于LinkedList

ArrayList和LinkedList新增元素

  • 从集合头部位置新增元素
    • ArrayList是数组实现的,在添加元素前,需要对头部后的数据进行复制,所以效率很低
    • LinkedList是基于链表实现,在添加元素前,首先会通过循环查找到添加元素的位置,直接新增不需要进行复制。LinkedList添加元素到头部是非常高效的。
  • 从集合中间位置新增元素
    • ArrayList在添加元素到数组中间时,同样有部分数据需要复制,效率也不高
    • LinkedList将元素添加到中间位置,是添加元素最低效率的,因为靠近中间位置,在添加元素之前的循环查找是遍历元素最多的操作。
  • 从集合尾部位置新增元素
    • 添加元素到尾部的操作中,在没有扩容的情况下,ArrayList的效率要高于LinkedList
    • 这是因为ArrayList在添加元素到尾部的时候,不需要复制重排数据,效率非常高。
    • LinkedList虽然也不用循环查找元素,但LinkedList中多了new对象以及变换指针指向对象的过程,所以效率要低于ArrayList

ArrayList和LinkedList删除元素

  • 从集合头部位置删除元素
  • 从集合中间位置删除元素
  • 从集合尾部位置删除元素

ArrayListLinkedList的删除的过程与新增过程的原理一样

ArrayList和LinkedList遍历元素

  • for(;;)循环
    • LinkedListfor循环性能是最差的,而ArrayListfor循环性能是最好的。
  • 迭代器迭代循环
    • LinkedList的迭代循环遍历和ArrayList的迭代循环遍历性能相当,也不会太差,所以在遍历LinkedList时,要切忌使用for循环遍历

合理使用Stream

  • 循环迭代次数较少的情况下,常规的迭代方式性能反而更好;
  • 单核CPU服务器配置环境中,也是常规迭代方式更有优势;
  • 而在大数据循环迭代中,如果服务器是多核CPU的情况下,Stream的并行迭代优势明显

我们在平时处理大数据的集合时,应该尽量考虑将应用部署在多核CPU环境下,并且使用Stream的并行迭代方式进行处理。

HashMap

在使用HashMap时,可以结合自己的场景来设置初始容量和加载因子两个参数

  • 当查询操作较为频繁时,我们可以适当地减少加载因子
  • 如果对内存利用率要求比较高,我可以适当的增加加载因子

我们还可以在预知存储数据量的情况下,提前设置初始容量(初始容量=预知数据量/加载因子)。这样做的好处是可以减少 resize() 操作,提高HashMap的效率。