2
头图

  CRUD麻木了吗?被xxx吐槽系统慢吗?你真的了解你的代码吗?今天聊聊一些关于java性能的细节。
3614785154e54acb962defa55ba781c5.jpg

部分内容来自这个网站:http://java-performance.com,英文比较好的小伙伴可以直接看原文,我今天的内容是自己总结和部分翻译的结合物。

正篇

一、java中正则表达式相关优化

  1. 使用Matcher和Pattern进行预编译,替换String.matches, split, replaceAll, replaceFirst等方法,避免不必要的pattern编译。

二、java.util.LinkedList性能

  1. 考虑使用ArrayDeque用于基于队列的算法替换LinkedList,性能优于LinkedList;
  2. 使用ListIterator(forEach)遍历LinkedList【链表特性】;
  3. 避免任何接受或返回列表中元素索引的LinkedList方法【类似获取index的操作】,性能很差,遍历列表实现;
  4. 使用pollFirst/pollLast替换LinkedList.remove/removeFirst/removeLast方法。

三、java.util.Date, java.util.Calendar and java.text.SimpleDateFormat performance日期的存储,解析和转换

  1. 除非您必须使用java.util.Date,否则不要使用它。改用普通的long。
  2. java.util.Calendar可用于各种日期计算,但要避免存储大量此类对象或广泛创建它们——它们消耗了大量内存,创建成本高昂。
  3. java.text.SimpleDateFormat适用于一般案例日期时间解析,但如果您必须以相同的格式解析大量日期(特别是没有时间的日期),最好避免它。改为手动实现解析器。

    相关的优化案例可以参考:https://github.com/alibaba/ar...,案例中还包含了List操作的一些优化。

四、使用Joda Time类库进行时间处理,在某些方面性能更好

五、java.io.ByteArrayOutputStream,不应该在性能关键代码中使用ByteArrayOutputStream

  1. 对于性能关键型代码,请尝试使用ByteBuffer而不是ByteArrayOutputStream。如果您仍然想使用ByteArrayOutputStream-请取消其同步。
  2. 在大多数情况下,避免使用ByteArrayOutputStream.toByteArray方法——它创建一个内部字节数组的副本。如果您的应用程序使用几千兆字节内存,收集这些副本的垃圾可能需要相当长的时间。

六、java.io.BufferedInputStream, java.util.zip.GZIPInputStream, java.nio.channels.FileChannel:这两个流中的一些小性能陷阱

  1. BufferedInputStream和GZIPInputStream都有内部缓冲区。前者的默认大小为8192字节,后者的默认大小为512字节。一般来说,值得将任何尺寸增加到至少65536。(减少BufferedInputStream,GZIPInputStream自动扩容的性能损耗)

七、各种通用压缩算法的性能——其中一些速度惊人(LZ4)

  1. 如果您认为数据压缩速度非常缓慢,请检查LZ4(快速)实现,该实现能够以约320 Mb/秒的速度压缩文本文件——对于大多数应用程序来说,这种速度的压缩不应该很明显。如果可能,将LZ4压缩缓冲区大小增加到32M限制是有意义的(请记住,您需要一个类似大小的缓冲区进行解压缩)。您还可以尝试将2个具有32M缓冲区大小的LZ4BlockOutputStream-s链起来,以充分利用LZ4。
  2. 如果您被限制使用第三方库或想要更好的压缩,请检查JDK deflate(lvl=1)【实现类:java.util.zip.DeflaterOutputStream / InflaterInputStream】编解码器——它能够以~75 Mb/秒的速度压缩同一文件。

八、ava.util.Map、java.util.Set及其大多数实现的优化(尽量避免使用contains)

  1. 对于集合,contains+add/remove调用对应替换为单个add/remove调用;
  2. 对于Map,避免contains+get使用,替换为get,然后是get结果的null检查。contains+remove对应替换为单个remove调用并检查其结果。【另:ConcurrentHashMap的containsKey方法本身就是get方法实现的】

九、单线程和多线程环境中的java.util.Random和java.util.concurrent.ThreadLocalRandom概述

  • 在任何情况下,都不要在多个线程之间共享java.util.Random的实例,而是将其包装在ThreadLocal中。

十、使用Apache Commons StringUtils.replace而不是String.replace

  1. 如果代码中存在大量的替换操作,考虑使用StringUtils。StringUtils远远胜过了 Java 8 的 String.replace 方法。
    // replace this
    test.replace(“test”, “simple test”);
    // with this
    StringUtils.replace(test, “test”, “simple test”);

十一、使用double/long替换BigDecimal

  1. 尽可能使用较小的货币单位,比如(角,分),使用double或long保存;

    之前在stackoverflow上看到有个老哥说BigDecimal比double慢了1000倍,没有实践过,总之BigDecimal性能差是不争的事实。
    image.png
  2. 四舍五入截取小数位长度(在使用尽可能小的单位前提下);
  3. 避免double转换成BigDecimal,如果要转换使用String转换BigDecimal;

0d385ed3079c4e199f3524d6d44e5602.jpg


开翻挖掘机
225 声望26 粉丝

不忘初心❤️,且行且思考