关于java:Java性能优化的十条小技巧

5次阅读

共计 2728 个字符,预计需要花费 7 分钟才能阅读完成。

1 System.nanoTime

测试性能时,System.nanoTimeSystem.currentTimeMills 更准确,前者应用纳秒计时,且对系统影响更小。

具体来说:

  • System.currentTimeMills返回自 1970 年 1 月 1 日 以来通过的毫秒数,返回的精度与操作系统无关
  • System.nanoTime:不是事实工夫,是虚拟机提供的计时工夫,准确到纳秒

2 ThreadLocalRandom

通常生成随机数会应用 Random 类,Random是线程平安的,Random实例外面有一个原子性的种子变量来记录以后种子的值,当要生成新的随机数时,会依据以后种子计算新的种子并更新回原子变量。多线程下计算新种子,会竞争同一个原子变量的更新操作,会造成大量线程进行自旋测试,升高并发性能。

ThreadLocalRandom 在以后线程保护了一个种子,适宜在多线程场景下提供高性能的伪随机数生成,应用如下:

ThreadLocalRandom random = ThreadLocalRandom.current();
random.nextInt(range);

3 应用局部变量

实践上说,拜访局部变量会快于类变量,因为局部变量保留在办法栈中,而类变量保留在堆中。如果在某个类办法中须要屡次拜访类变量,倡议先创立一个局部变量并使其具备与类变量雷同的值。

4 对于正则表达式替换

因为正则表达式替换时每次都须要编译正则表达式到一个两头构造,因而比惯例的间接替换要慢,如果是固定的正则表达式替换,能够采纳预编译的思维:

Pattern pattern = Pattern.compile("origin str");
public String replace(String str){return pattern.matcher(str).replaceAll("target str");
}

而不是采纳:

public String replace(String str){return str.replace("origin str","target str");
}

5 对于字符串拼接

尽可能应用如下模式:

String a = "xxx";
String b = "xxx";
String c = new StringBuilder().append(a).append(b).toString();

性能绝对不好的是如下情景(得益于 JVM 默认开启字符串拼接优化):

String c = a+b;

性能最差的是:

StringBuilder c = new StringBuilder();
c.append(a);
c.append(b);
String result = c.toString();

因为这样 JIT 不会优化。

另外,在无关线程平安的状况下,尽可能应用 StringBuilder 而不是StringBuffer

6 对于数字转字符串

intString 是一个较为耗时的操作,尽量避免不必要的转化,如果的确须要,能够事后将一批 int 转为String,须要的时候间接取出:

public static class CommonUtil{
    static int cacheSize = 1024;
    static String [] caches = new String[cacheSize];
    static{for(int i=0;i<cacheSize;++i){caches[i] = String.valueOf(i);
        }
    }
    public static String int2String(int data){if(data < cacheSize){return caches[size];
        }else{return String.valueOf(data);
        }
    }
}

这样相比起间接应用

Stirng.valueOf(data)

性能会高一点。

7 switch/if

少分支的状况下,倡议应用if,多分支倡议应用switch,罕用的“少分支”规范是2- 5 个

8 采纳返回码而不是抛异样

除非必要应用异样,应该防止把失常的返回谬误后果应用异样来代替。抛异样会导致性能是因为结构异样对象时须要一个填写异样栈的过程,就是 Throwable 中的 fillInStackTrace,这是一个Native 办法,会填写异样栈,造成较为重大的耗时。

一种优化办法是,自定义异样,重写fillInStackTrace()

public class MyException extends RuntimeException{
    ...
    public synchronized Throwable fillInStackTrace(){this.setStackTrace(new StackTraceElement[0]);
        return this;
    }
}

另外,JVM会对频繁抛出的异样做 Fast Throw 优化,如果检测到代码中某一地位间断屡次抛出同一类型的异样,则采纳 Fast Throw 形式,异样栈信息不会被填写,这种异样抛出速度很快,因为不须要在堆里分配内存,也不须要结构残缺的异样栈信息,默认对如下异样采纳 Fast Throw 优化:

  • NullPointerException
  • ArithmeticException
  • ArrayIndexOutOfBoundsExpcetion
  • ArrayStoreException
  • ClassCastException

须要留神的是,Fast Throw尽管进步了性能,然而会导致异样栈音讯,从而无奈疾速定位到错误代码,如果须要防止异样栈优化,能够应用参数:

-XX:-OmitStackTraceInFastThrow

9 位运算

能够通过位运算代替局部算术运算以进步性能,比方:

  • 判断奇数:(a & 1) == 1
  • 判断偶数:(a & 1) == 0
  • 除 2:a>>1
  • 乘 2:a<<1

10 其余技巧

  • 字符串搜寻等须要搜寻单个字符时,应用 String.indexOf(char) 而不是String.indexOf(String)
  • 对于判断一些非凡的 ID,比方长度 9 位 且以 11 结尾,能够间接应用常数判断:id>=110_000_000 && id<=120_000_000,而不须要通过 String.valueOf 转为字符串再通过 String.length+String.startWith 判断
  • switch 中,能够应用 int 去代替String
  • 日志输入能够间接应用字符串拼接而不是 模板 +{},因为会有一个占位符 {} 替换成指标变量的耗时过程,被频繁调用的话倡议间接字符串拼接
  • 传输的实体类尽量避免应用 String,因为其中波及序列化、反序列化、字符串结构,而对于byte[] 结构 String 的办法,外部会调用 StringCoding.decode,相比起通过char[]/Stirng 结构会造成更大的耗时
正文完
 0