原创

Java程序性能优化

1. 字符串分割,谁更胜一筹?

方式一,经常用 String 提供的 split() 方法来满足业务需求。
代码模拟了一些数据,然后程序跑起来,花费大约 3000 多毫秒。
方式二,采用字符串分割的工具类 StringTokenizer
采用 StringTokenizer 完成 split() 同样的数据分割,花费大约 500 毫秒。

2. 字符串拼接,哪种方式更优?

方式一,使用 + 号拼接字符串。
程序跑起来,大约花费 27687 毫秒。
方式二,使用 StringBuilder 进行拼接字符串。
程序跑起来,大约花费 24 毫秒。
很显然,使用 + 号拼接字符串,其效率明显较低,采用 StringBuilder 来完成字符串连接性能相对较好,同理,如果需要考虑线程安全的情况下,可以选择 StringBuffer。

3. 善用 arraycopy(),让数组复制不再难。

数组复制是研发过程中,使用较多的功能,JDK 中提供了 API 来实现。但是,哪种方式较好呢?
方式一,作为开发人员,没事就喜欢造轮子,代码会这么写。
方式二,采取 System.arraycopy() 来完成数组复制。
红色圈住部分,在本机跑起来验证,方式一、方式二,差距不是特别大,在数据量大的时候,System.arraycopy() 还是稍微好一点。
方式三,采取 Arrays.copyOf() 来完成数组的复制。
鉴于 Arrays.copyOf() 底层还是调用 System.arraycopy() 来实现,性能肯定稍逊色于直接调用 System.arraycopy() 来完成数组复制。
所以,对数组的操作,如果能用 System.arraycopy() 这个方法实现,建议尽量去使用。

4. 关注循环体,别做重复劳动。

尽可能让程序少做重复的计算,尤其要重点关注循环体内的代码。
举个简单的栗子,上面代码段中,Math.PI * Math.sin(k) 的执行在循环体中重复执行,而且执行结果是唯一的,可以考虑提到循环体外。
本机进行验证时,前者大约花费 30 毫秒,而调整后,大约花费 2 毫秒,性能提升还是有的。
所以,从循环体内提取重复的代码,可以有效的提升系统性能。
另外,在阿里开发手册中强烈推荐,循环体中的语句要考量性能,以下操作尽量移至循环体外处理,如定义对象、变量、获取数据库连接,进行不必要的 try-catch 操作(这个 try-catch 是否可以移至循环体外)。

5.考虑使用静态方法。

如果你没有必要去访问对象的外部,那么就使你的方法成为静态方法。她会被更快地调用,因为她不需要一个虚拟函数导向表。这同事也是一个很好的实践,因为她告诉你如何区分方法的性质,调用这个方法不会改变对象的状态。

6. 缓冲,让子弹飞一会儿。

缓冲,最常用的场景就是提高 I/O 的速度,解决 I/O 性能瓶颈。在
Java 中对不少 I/O 组件都提供了缓冲功能。
例如,采用 FileWriter 向文件中写入数据。
程序跑起来,花费大约 8212 毫秒。那么,再来看看加入缓冲之后会有什么效果?使用BufferedWriter
程序跑起来,花费大约 4143 毫秒,性能提升了一倍。
所以,文件读写操作时尽量都使用缓冲流进行操作,有助于提升性能。

7.避免方法过长.

我们在定义一个方式的时候,应该考虑到一个方法不应该太长,它就应该是专门是来执行单一功能的。这样其实对维护和性能都有好处。
一方面,从维护角度来说,适当长度的方法易读性更强,更容易理解;另一方面,在类的加载和方法调用的过程中,方法会被加载到内存中。如果一个方法太大,处理起来就需要消耗额外的内存和CPU周期。我们应该学会在恰当的逻辑点上将一个长方法拆开。

8. 日志记的好,线上没烦恼。

推荐:谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使 用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志。
说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。
记录日志时请思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?
一个优化原则。先实现业务功能,再考虑优化性能,如果功能都没实现,谈其它的都白扯。

9.避免多个if-else语句

对于这个优化点,大家应该很熟悉了。但是实际在写代码的时候,还是if-else一撸到底。
这样做的话,其实也会影响性能。因为JVM必须对条件进行比较。如果在for、while等循环语句中使用同样的条件,情况会变得更糟糕。
如果我们的业务逻辑中有很多的条件,我们可以尝试着将这些条件分组并且返回一个布尔值,然后再将其用于if语句。
另外,如果可能的话,我们可以考虑使用switch语句来代替多个if-else。switch语句比if-else有性能优势。

总结:一个调优思路总结。

**首先从系统设计层面,去看看是否有改进的可能,是不是可以引入一些设计模式、是不是可以引入缓存机制等方法,来屏蔽潜在的性能问题。(设计调优)
**然后从代码层面,看看代码是否有优化的可能。(代码调优)
**接着去看看 Java 程序运行的环境,也就是通过调整 JVM 的参数来提升一下性能。(jvm调优)
**接着到数据库层面,看看是否有调优的可能。(数据库调优)
**最后到操作系统层面,看看是否可以进行调优。(操作系统调优)

本文链接地址:http://www.ysxbohui.com/article/32

正文到此结束