美文网首页
JAVA代码的调优思路

JAVA代码的调优思路

作者: 大树8026 | 来源:发表于2020-03-27 22:41 被阅读0次

    文中代码引用极客时间:《Java性能调优实战》-刘超 版权侵删
    一、String的使用
    1.1 了解一下String的原理
    JDK1.6:char[]、offset、hash、count
    JDK7/8:char[]、offset
    JDK9:byte[]、coder、offset

    1.2 字符串对象优化
    1.2.1构建大对象时,尽量用StringBuilder对象
    1.2.2intern()的使用,str.intern()的一次调用,将查看字符串常量区有没有str的字符串,如果有就直接获得该常量区的引用,如果没有就将字符串放到字符串常量区。

    String str1= "abc";
    String str2= new String("abc");
    String str3= str2.intern(); #将str3的引用指向字符串数据的地址,该地址在常量区
    assertSame(str1==str2);#false
    assertSame(str2==str3);#false
    assertSame(str1==str3);#true
    

    字符串常量区的实现是一个类似于HashTable的实现,当数据量比较大的时候,ygc耗时会越来越长。

    二、正则表达式
    2.1介绍
    java对正则表达式公式进行语法分析,建立一个语法分析树,根据该语法树结合正则表达式引擎生成执行程序,用于匹配字符串。
    正则表达式引擎实现有两种方式:DFA(Deterministic Final Automaton确定有限状态自动机)和NFA(None deterministic Final Automaton非确定性有状态自动机)。性能上DFA比NFA的时间复杂度小,但是NFA的功能性比较强,可支持group等功能。

    2.2NFA的自动回溯
    NFA的贪婪模式(使用了+、?、*、{min,max},正则表达式会尽可能的匹配多的字符串)会出现回溯,大量的回溯会长期占用CPU,从而带来性能开销。
    举例来说

    String str = "abbc";
    String regx = "ab{1,3}c"
    

    匹配过程如下:
    1)、拿正则表达式的第一个匹配符“a”和str匹配,发现a和str的第一个字符串匹配,进行接下来的匹配;
    2)、拿正则表达式的第二个匹配符“b{1,3}”和str匹配,发现str的第一个b匹配,第二b匹配;
    3)、拿str的c和“b{1,3}”匹配时,发现不匹配;
    4)、拿str的c和正则表达式的c匹配,发现匹配;结束。

    以上步骤中3和4过程str的c字符两次被用来做对比,此处发生回溯。

    2.3避免自动回溯
    2.3.1懒惰模式在(+、?、*、{min,max})这些字符串后加?,可以减小回溯范围,举例说明:

    String str = "abbc";
    String regx = "ab{1,3}?c";
    

    匹配过程如下:
    1)、拿正则表达式的第一个匹配符“a”和str匹配,发现a和str的第一个字符串匹配,进行接下来的匹配;
    2)、拿正则表达式的第二个匹配符“b{1,3}”和str的第一个“b”匹配,发现匹配到字符;
    3)、拿正则表达式的第三个匹配符“c”和str的第二个“b”匹配,发现不匹配;
    4)、(也是回溯)拿正则表达式的第二个匹配符“b{1,3}”和str的第二个“b”匹配;
    5)、拿正则表达式的第三个匹配符“c”和str的“c”匹配,发现匹配,匹配结束。

    2.3.2独占模式
    同贪婪模式一样,独占模式一样会最大限度地匹配更多内容;不同的是,在独占模式下,匹配失败就会结束匹配,不会发生回溯问题。

    String text=“abbc”
    String regex=“ab{1,3}+bc”
    

    2.3正则表达式的优化
    2.3.1. 少用贪婪模式,多用独占模式
    2.3.2减少分支选择
    分支选择类型“(X|Y|Z)”的正则表达式会降低性能,我们在开发的时候要尽量减少使用。如果一定要用,我们可以通过以下几种方式来优化:
    1.我们需要考虑选择的顺序,将比较常用的选择项放在前面,使它们可以较快地被匹配;
    2.将“(abcd|abef)”替换为“ab(cd|ef)”;
    3.如果是简单的分支选择类型,我们可以用三次 index 代替“(X|Y|Z)”,如果测试的话,你就会发现三次 index 的效率要比“(X|Y|Z)”高出一些
    2.3.3 减少捕获嵌套

    
    public static void main( String[] args )
    {
      String text = "<input high=\"20\" weight=\"70\">test</input>";
      String reg="(?:<input.*?>)(.*?)(?:</input>)"; #使用“(?:X)”代替“(X)”
      Pattern p = Pattern.compile(reg);
      Matcher m = p.matcher(text);
      while(m.find()) {
        System.out.println(m.group(0));//整个匹配到的内容
        System.out.println(m.group(1));//(.*?)
      }
    }
    

    三、ArrayListOrLinkedList
    3.1 ArrayList
    Q1:transient 关键字修饰该字段则表示该属性不会被序列化,但 ArrayList 其实是实现了序列化接口,这到底是怎么回事呢?
    A1:ArrayList是基于数组,动态扩展的,不是每个被分配的空间都存储了数据,如果采用了外部序列的方式会序列化整个数组,包括没有存储数据的空间。因此需要用transient关键字修饰这个数组;

    3.2性能对比(https://github.com/nickliuchao/collection
    3.2.1ArrayList 和 LinkedList 新增元素操作测试:
    从集合头部位置新增元素
    从集合中间位置新增元素
    从集合尾部位置新增元素

    测试结果 (花费时间):
    ArrayList>LinkedList
    ArrayList<LinkedList
    ArrayList<LinkedList

    3.2.2ArrayList 和 LinkedList 删除元素操作测试
    从集合头部位置删除元素
    从集合中间位置删除元素
    从集合尾部位置删除元素

    测试结果 (花费时间):
    ArrayList>LinkedList
    ArrayList<LinkedList
    ArrayList<LinkedList

    3.2.3
    for(;;) 循环
    迭代器迭代循环

    测试结果 (花费时间):
    ArrayList<LinkedList
    ArrayList≈LinkedList

    相关文章

      网友评论

          本文标题:JAVA代码的调优思路

          本文链接:https://www.haomeiwen.com/subject/lxcduhtx.html