搬砖者:为什么程序总是那么慢?它现在到底在干什么?时间都花到哪里去了?

面试官:简单谈谈 Java 程序性能优化?

1.

字符串处理优化,乃优化之源。

研发过程中,String 的 API 用的应该是最多,创建 String 对象,以及字符串分割处理那是常有的事儿。

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

字符串分割,常用的方式有哪些?哪种方式好一些?

方式一,经常用 String 提供的 split() 方法来满足业务需求。

代码模拟了一些数据,然后程序跑起来,花费大约 3000 多毫秒。

方式二,采用字符串分割的工具类 StringTokenizer。

采用 StringTokenizer 完成 split() 同样的数据分割,花费大约 500 毫秒。

从运行效果, StringTokenizer 其效率高于 split() 方法。所以,在能够使用 StringTokenizer 进行处理的地方,就尽量使用 StringTokenizer 进行字符串分割处理。

另外,平时研发中,需要注意一点,在使用索引访问用 String 的 split() 方法得到的数组时,需做最后一个分隔符后有无内容的检查,否则会有抛异常的风险。

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

方式一,使用 + 号拼接字符串。

程序跑起来,大约花费 27687 毫秒。

方式二,使用 StringBuilder 进行拼接字符串。

程序跑起来,大约花费 24 毫秒。

很显然,使用 + 号拼接字符串,其效率明显较低,采用 StringBuilder 来完成字符串连接性能相对较好,同理,如果需要考虑线程安全的情况下,可以选择 StringBuffer。

另外,在阿里开发手册中也强烈推荐,在循环体内,字符串的连接方式,使用 StringBuilder 的 append 方法进行扩展。如果采取 + 号拼接,会造成内存资源浪费。

2. 

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

数组复制是研发过程中,使用较多的功能,JDK 中提供了 API 来实现。但是,哪种方式较好呢?

方式一,作为开发人员,没事就喜欢造轮子,代码会这么写。

方式二,采取 System.arraycopy() 来完成数组复制。

红色圈住部分,在本机跑起来验证,方式一、方式二,差距不是特别大,在数据量大的时候,System.arraycopy() 还是稍微好一点。

方式三,采取 Arrays.copyOf() 来完成数组的复制。

鉴于 Arrays.copyOf() 底层还是调用 System.arraycopy() 来实现,性能肯定稍逊色于直接调用 System.arraycopy() 来完成数组复制。

所以,对数组的操作,如果能用 System.arraycopy() 这个方法实现,建议尽量去使用。

3. 

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

尽可能让程序少做重复的计算,尤其要重点关注循环体内的代码。

举个简单的栗子,上面代码段中,Math.PI * Math.sin(k) 的执行在循环体中重复执行,而且执行结果是唯一的,可以考虑提到循环体外。

本机进行验证时,前者大约花费 30 毫秒,而调整后,大约花费 2 毫秒,性能提升还是有的。

所以,从循环体内提取重复的代码,可以有效的提升系统性能。

另外,在阿里开发手册中强烈推荐,循环体中的语句要考量性能,以下操作尽量移至循环体外处理,如定义对象、变量、获取数据库连接,进行不必要的 try-catch 操作(这个 try-catch 是否可以移至循环体外)。

4. 

集合用的多,使用场景要注意。

业务研发中,集合家族的 API 使用频率相当之高。那么,充分的选择好数据结构进行数据存储,便是最好的程序优化

为了更清晰的说清各自的使用场景,也为了更好的助你掌握,梳理成思维导图。

4.1. List 家族,谁能得宠?

4.2. Map 家族,谁占鳌头?

另外,在集合初始化时,要指定集合初始值大小。

说明:HashMap 使用 HashMap(int initialCapacity) 初始化。

正例:initialCapacity = (需要存储的元素个数 / 负载因子) + 1。

注意负载因子(即 loader factor)默认为 0.75,如果暂时无法确定初始值大小,请设置为 16(即默认值)。

反例:HashMap 需要放置 1024 个元素,由于没有设置容量初始大小,随着元素不断增加,容 量 7 次被迫扩大,resize 需要重建 hash 表,严重影响性能。

—— 阿里开发手册

4.2. Set 家族,谁最适配?

图中已经把常用的数据结构列举了出来,就不再一一去写代码验证啦。还是那句话,选择好数据结构进行数据存储,便是最好的程序优化。

5. 

缓冲,让子弹飞一会儿。

缓冲,最常用的场景就是提高 I/O 的速度,解决 I/O 性能瓶颈。在

Java 中对不少 I/O 组件都提供了缓冲功能。

例如,采用 FileWriter 向文件中写入数据。

程序跑起来,花费大约 8212 毫秒。那么,再来看看加入缓冲之后会有什么效果?

程序跑起来,花费大约 4143 毫秒,性能提升了一倍。

所以,文件读写操作时尽量都使用缓冲流进行操作,有助于提升性能。

6. 

缓存,让坐飞机的和坐驴车的打交道。

在实际项目研发中,缓存也是经常使用到,缓存是为了提升系统性能而开辟的内存空间。

最为简单的缓存可以直接使用 HashMap 实现,例如应用的配置信息,在启动的时候都加载进去。

针对银行编码等一些使用频率较高的业务数据,或者来之不易的计算结果,都可以保存到缓存中,当再次使用时,直接从缓存中获取,而不需要再占用宝贵的系统资源。

目前有很多基于 Java 的缓存框架,而我用的最多的是 EhCache。

7. 

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

推荐:谨慎地记录日志。生产环境禁止输出 debug 日志;有选择地输出 info 日志;如果使 用 warn 来记录刚上线时的业务行为信息,一定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志。

说明:大量地输出无效日志,不利于系统性能提升,也不利于快速定位错误点。

记录日志时请思考:这些日志真的有人看吗?看到这条日志你能做什么?能不能给问题排查带来好处?

—— 阿里开发手册

8. 

杂七杂八,啰嗦一句不嫌多。

一个优化原则。先实现业务功能,再考虑优化性能,如果功能都没实现,谈其它的都白扯。

一个调优思路。

  • 首先从系统设计层面,去看看是否有改进的可能,是不是可以引入一些设计模式、是不是可以引入缓存机制等方法,来屏蔽潜在的性能问题。

  • 然后从代码层面,看看代码是否有优化的可能。

  • 接着去看看 Java 程序运行的环境,也就是通过调整 JVM 的参数来提升一下性能。

  • 接着到数据库层面,看看是否有调优的可能。

  • 最后到操作系统层面,看看是否可以进行调优。

好了,本次的分享,就到这里,希望你们喜欢。

Java 程序该怎么优化?(技巧篇)的更多相关文章

  1. Java 程序该怎么优化?(工具篇)

    程序员:为什么程序总是那么慢?时间都花到哪里去了? 面试官:若你写的 Java 程序,出现了性能问题,该怎么去排查呢? 工欲善其事必先利其器,为你呈上一箩筐性能优化工具,必有一款满足你,废话不多说,直 ...

  2. Java 程序该怎么优化?(实战篇)

    面试官:出现了性能问题,该怎么去排查呢? 程序猿:接口响应那么慢,时间都花到哪里去了? 运维喵:为什么你的应用跑着跑着,CPU 就接近 100%? 分享一些真实生产问题排查故事,看看能否涨姿势,能否 ...

  3. Java 程序该怎么优化?(命令篇)

    灵魂拷问,JDK 提供的命令,除了 java.javac,你还用过哪些命令呢? 灵魂再拷问,若你写的 Java 程序,出现了性能问题,该怎么去排查呢? Java 作为编程语言中的战斗机,JDK 默认已 ...

  4. eclipse调试java程序的九个技巧

    转:http://www.cnblogs.com/lingiu/p/3802391.html 九个技巧: 逻辑结构 条件debug 异常断点 单步过滤 跳到帧 Inspect expressions ...

  5. 使用 Eclipse 调试 Java 程序的 10 个技巧

    你应该看过一些如<关于调试的N件事>这类很流行的帖子 .假设我每天花费1小时在调试我的应用程序上的话,那累积起来的话也是很大量的时间.由于这个原因,用这些时间来重视并了解所有使我们调试更方 ...

  6. 【转】使用 Eclipse 调试 Java 程序的 10 个技巧

    你应该看过一些如<关于调试的N件事>这类很流行的帖子 .假设我每天花费1小时在调试我的应用程序上的话,那累积起来的话也是很大量的时间.由于这个原因,用这些时间来重视并了解所有使我们调试更方 ...

  7. 【Eclipse】调试java程序的九个技巧

    本文转自[半夜乱弹琴],原文地址:http://www.cnblogs.com/lingiu/p/3802391.html 九个技巧: 逻辑结构 条件debug 异常断点 单步过滤 跳到帧 Inspe ...

  8. eclipse debug调试java程序的九个技巧

    九个技巧: 逻辑结构 条件debug 异常断点 单步过滤 跳到帧 Inspect expressions display 远程debug 最早开始用eclipse的debug的时候,只会F5 F6 F ...

  9. (转)eclipse调试java程序的九个技巧

    转自:http://www.cnblogs.com/lingiu/p/3802391.html 九个技巧: 逻辑结构 条件debug 异常断点 单步过滤 跳到帧 Inspect expressions ...

随机推荐

  1. 峰哥说技术:01-Spring Boot介绍

    Spring Boot深度课程系列 峰哥说技术—2020庚子年重磅推出.战胜病毒.我们在行动 Spring Boot介绍 A.Spring Boot是什么? 由于Spring是一个轻量级的企业开发框架 ...

  2. 吐血干货,直播首屏耗时400ms以下的优化实践

    导读: 直播行业的竞争越来越激烈,进过18年这波洗牌后,已经度过了蛮荒暴力期,剩下的都是在不断追求体验.最近在帮做直播优化首开,通过多种方案并行,把首开降到500ms以下,希望能对大家有借鉴. 背景: ...

  3. .NET Conf: Xamarin专场会议3.23 开幕

    聚焦于 Xamarin 的 NET Conf 是一项免费的为期一天的直播活动,来自社区和.NET产品团队的演讲者正在使用Xamarin技术构建本机移动应用程序!Xamarin允许您使用C#(而不是Ja ...

  4. 网页外链用了 target="_blank",结果悲剧了

    今天给大家分享一个 Web 知识点.如果你有过一段时间的 Web 开发经验,可能已经知道了.不过对于刚接触的新手来说,还是有必要了解一下的. 我们知道,网页里的a标签默认在当前窗口跳转链接地址,如果需 ...

  5. C 和 C++语言中的内存拷贝函数memcpy()

    memcpy指的是C和C++使用的内存拷贝函数 函数原型为void *memcpy(void *destin, void *source, unsigned n): 函数的功能是从源内存地址的起始位置 ...

  6. 左侧带三角的Card css支持hover阴影

    <div class="inputReportIndex"> <div class="inner"> <div class=&qu ...

  7. 文件合并cat and paste

    cat 纵向合并 cat file1 file 2 paset横向合并 wc用法 sort用法

  8. http详解和分析

    1.http是什么? http 是一种超文本传输协议原名是这个Hypertext Transfer Protocol -- HTTP/1.1 可以百度查看http的RFC文档编号为RFC-2616 连 ...

  9. 在vscode中怎样debug调试go程序

    随着互联网时代的飞速发展,我们编码使用的开发利器也在不断更新换代,古话说工欲善其事必先利其器,对于Java开发者而言,eclipse和idea这两款神器各有千秋,因自己的爱好可以选取不同的IDE,但是 ...

  10. Java井字棋游戏

    试着写了一个井字棋游戏,希望各位能给予一些宝贵的建议. 一.棋盘类 package 井字棋游戏; public class ChessBoard { private int number; Perso ...