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

面试官:简单谈谈 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. 简单谈谈HashMap

    概述 面试Java基础,HashMap可以说是一个绕不过去的基础容器,哪怕其他容器都不问,HashMap也是不能不问的. 除了HashMap,还有HashTable跟ConcurrentHashMap ...

  2. 桌面运维之Windows快捷键,每一个工程师都是“快捷键”的工程师!

    1.win快捷键 首先教大家win7新增的3D效果: Win + Tab 快速切换已打开的程序(和Alt+tab一样的效果) Win + Home 将所有使用中窗口以外的窗口最小化 Win + Spa ...

  3. RestTemplate 负载均衡原理

    RestTemplate 是通过拦截器改变请求的URI的方式来指定服务器的,此处将通过一个自定义LoadBalanced的方式来进行说明 1.导入jar包 <parent> <gro ...

  4. 负margin在页面布局中的应用

    关于负margin的原理建议大家看看这篇文章:http://www.cnblogs.com/2050/archive/2012/08/13/2636467.html#2457812 一. 左右列固定, ...

  5. 「从零单排HBase 04」HBase高性能查询揭秘

    先给结论吧:HBase利用compaction机制,通过大量的读延迟毛刺和一定的写阻塞,来换取整体上的读取延迟的平稳. 1.为什么要compaction 在上一篇 HBase读写 中我们提到了,HBa ...

  6. 小白学 Python 数据分析(15):数据可视化概述

    人生苦短,我用 Python 前文传送门: 小白学 Python 数据分析(1):数据分析基础 小白学 Python 数据分析(2):Pandas (一)概述 小白学 Python 数据分析(3):P ...

  7. 本地Hadoop集群搭建

    什么是Hadoop? Hadoop是一个开源的Apache项目,通常用来进行大数据处理. Hadoop集群的架构: master节点维护分布式文件系统的所有信息,并负责调度资源分配,在Hadoop集群 ...

  8. css3 scale 缩放出现 1px 问题

    问题描述 先来一段html代码 <div class="container"> <div class="parent"> <div ...

  9. Redis06——Redis到底能用在什么地方(上)

    之前我们介绍了一些列关于Redis的数据结构.持久化.过期&淘汰策略.集群化等知识点,感兴趣的小伙伴可以在文章的末尾查看往期内容.今天将为大家带来Redis的应用.由于本篇文章较长,所以将拆分 ...

  10. 在 centos6 上安装 LAMP

    LAMP 代表的是 Linux, Apache, MySQL, 以及 PHP.   第一步,安装 Apache 使用 yum 安装 sudo yum install httpd 启动 httpd 服务 ...