Java性能优化常识

简介:

9.1 前提
首先让程序运行起来,再考虑变得更快——但只有在自己必须这样做、而且经证实
在某部分代码中的确存在一个性能瓶颈的时候,才应进行优化。除非用专门的工具分析
瓶颈,否则很有可能是在浪费自己的时间。性能提升的隐含代价是自己的代码变得难于
理解,而且难于维护。
对于像字符串的连接操作不使用“+”而使用专有方法 concat 等其他方法,这类问
题,则不能称为性能优化,而只能叫做基本常识。因而这类问题的解决并不能影响程序
的可读性和易维护性,所以我们提倡为性能优化打基础。以下将介绍一些常识:


9.2 运算时间


标准时间 = 语句执行时间/本地赋值时间


9.3 java.lang.String
字串的开销:字串连接运算符“+”看似简单,但实际需要消耗大量系统资源。编
译器可高效地连接字串,但变量字串却要求可观的处理器时间。该操作要创建并拆除一
个StringBuffer 对象以及一个String 对象。
上述问题的通常解决方法是新建一个StringBuffer(字串缓冲),用append 方法追加
自变量,然后用toString()将结果转换回一个字串。当要追加多个字串,则可考虑直接使
用一个字串缓冲——特别是能在一个循环里重复利用它的时候。通过在每次循环里禁止
新建一个字串缓冲,可节省980 单位的对象创建时间(见上表)。
更有效的解决办法是:在构造 StringBuffer 时,应该粗略的估计出它最终的总长度。默
认构造函数预设了16 个字符的缓存容量。append()方法首先计算字符串追加完成后的总长
度,如果这个总长度大于StringBuffer 的存储能力,append()方法调用私有的expandCapacity()
方法。expandCapacity()方法在每次被调用时使StringBuffer 存储能力加倍,并把现有的字符
数组内容复制到新的存储空间。存储能力的扩展,从而导致了两次代价昂贵的复制操作。
因此,我们至少有一点可以做得比编译器更好,这就是分配一个初始存储容量大于或者等
于最终字符长度StringBuffer。
因此,使用默认构造函数创建的StringBuffer 在字符串连接操作上的效率其实和用“+”
是一样的。如果首先估计出整个字符串最终的总长度,才会显著提高效率!
其他的字符串运算操作尽可能使用 String 已经提供的方法。比如,短字符串的连接可
以使用 concat;子串的查找可以使用 indexOf,substring 等。


9.4 java.util.Vector
一个Vector 就是一个java.lang.Object 实例的数组。Vector 与数组相似,它的元素可
以通过整数形式的索引访问。但是,Vector 类型的对象在创建之后,对象的大小能够根
据元素的增加或者删除而扩展、缩小。
1) 避免把新元素添加到Vector 的最前面
除非有绝对充足的理由要求每次都把新元素插入到Vector 的前面,否则对性能不
利。在默认构造函数中,Vector 的初始存储能力是10 个元素,如果新元素加入时存储
能力不足,则以后存储能力每次加倍。Vector 类就象StringBuffer 类一样,每次扩展存
储能力时,所有现有的元素都要复制到新的存储空间之中。
2) 避免从中间删除元素
由于Vector 中各个元素之间不能含有“空隙”,删除除最后一个元素之外的任意其
他元素都导致被删除元素之后的元素向前移动。也就是说,从Vector 删除最后一个元
素要比删除第一个元素“开销”低好几倍。
3) 删除所有元素的最好方法是 removeAllElements()
4) 避免二次搜索
假设Vector 类型的对象v 包含字符串“Hello”。考虑下面的代码,它要从这个Vector
中删除“Hello”字符串:
String s = "Hello";
int i = v.indexOf(s);
if(i != -1)
v.remove(s);
在这段代码中,indexOf()方法对v 进行顺序搜索寻找字符串“Hello”,remove(s)方法
也要进行同样的顺序搜索。改进之后的版本是:
String s = "Hello";
int i = v.indexOf(s);
if(i!= -1) v.remove(i);
这个版本中我们直接在remove()方法中给出待删除元素的精确索引位置,从而避免
了第二次搜索。一个更好的版本是:
String s = "Hello";
v.remove(s);
5) 循环内部的代码不会以任何方式修改Vector 类型对象大小时,应该提前取得
Vector.size()


9.5 线程
9.5.1 防止过多的同步
不必要的同步常常会造成程序性能的下降。因此,如果程序是单线程,则一定不
要使用同步。
9.5.2 避免同步整个代码段
对某个方法或函数进行同步比对整个代码段进行同步的性能要好。因为代码段的
同步牵涉的范围比对某个方法或函数进行同步广。
9.5.3 对每个对象使用多“锁”的机制来增大并发
一般每个对象都只有一个“锁”,这就表明如果两个线程执行一个对象的两个不同
的同步方法时,会发生“死锁”。即使这两个方法并不共享任何资源。为了避免这个问
题,可以对一个对象实行“多锁”的机制。


9.6 循环
9.6.1 边界
循环的边界是指完成所有循环操作的起点和终点。如果循环体内的操作不影响边
界,那么应该在循环体外,计算并且求得边界值。例如:
for(int i = 0; i < array.length; i++)
{
array[i]=i;
}
上述代码中每次循环操作,都要计算一次 array.length。
9.6.2 循环体内避免构建新对象
如果在循环体内用到新对象,需要在循环体开始以前构建好该对象。由标准时间
表可以看出构建对象有很大的系统消耗,并且在一次循环中还要清除掉该对象,下循
环再重新构建。
JAVA 编码规范 版本:0.0.0-1.1.1 第22页
沈阳东软软件股份有限公司 软件开发事业部
9.6.3 break
遍历数组、向量或者树结构时,如果满足条件的元素找到,一定要使用 break 语
句退出循环。


本文转自passover 51CTO博客,原文链接:http://blog.51cto.com/passover/425922,如需转载请自行联系原作者

相关文章
|
2月前
|
Java 测试技术 API
Java Stream API:被低估的性能陷阱与优化技巧
Java Stream API:被低估的性能陷阱与优化技巧
313 114
|
4月前
|
安全 Java 编译器
new出来的对象,不一定在堆上?聊聊Java虚拟机的优化技术:逃逸分析
逃逸分析是一种静态程序分析技术,用于判断对象的可见性与生命周期。它帮助即时编译器优化内存使用、降低同步开销。根据对象是否逃逸出方法或线程,分析结果分为未逃逸、方法逃逸和线程逃逸三种。基于分析结果,编译器可进行同步锁消除、标量替换和栈上分配等优化,从而提升程序性能。尽管逃逸分析计算复杂度较高,但其在热点代码中的应用为Java虚拟机带来了显著的优化效果。
134 4
|
4月前
|
机器学习/深度学习 Java 编译器
解锁硬件潜能:Java向量化计算,性能飙升W倍!
编译优化中的机器相关优化主要包括指令选择、寄存器分配、窥孔优化等,发生在编译后端,需考虑目标平台的指令集、寄存器、SIMD支持等硬件特性。向量化计算利用SIMD技术,实现数据级并行,大幅提升性能,尤其适用于图像处理、机器学习等领域。Java通过自动向量化和显式向量API(JDK 22标准)支持该技术。
185 4
|
4月前
|
数据采集 搜索推荐 Java
Java 大视界 -- Java 大数据在智能教育虚拟学习环境构建与用户体验优化中的应用(221)
本文探讨 Java 大数据在智能教育虚拟学习环境中的应用,涵盖多源数据采集、个性化推荐、实时互动优化等核心技术,结合实际案例分析其在提升学习体验与教学质量中的成效,并展望未来发展方向与技术挑战。
|
4月前
|
Cloud Native 前端开发 Java
WebAssembly 与 Java 结合的跨语言协作方案及性能提升策略研究
本文深入探讨了WebAssembly与Java的结合方式,介绍了编译Java为Wasm模块、在Java中运行Wasm、云原生集成等技术方案,并通过金融分析系统的应用实例展示了其高性能、低延迟、跨平台等优势。结合TeaVM、JWebAssembly、GraalVM、Wasmer Java等工具,帮助开发者提升应用性能与开发效率,适用于Web前端、服务器端及边缘计算等场景。
143 0
|
2月前
|
存储 缓存 Java
Java 12相比Java 11有哪些性能上的提升?
Java 12相比Java 11有哪些性能上的提升?
70 3
|
2月前
|
消息中间件 缓存 Java
Spring框架优化:提高Java应用的性能与适应性
以上方法均旨在综合考虑Java Spring 应该程序设计原则, 数据库交互, 编码实践和系统架构布局等多角度因素, 旨在达到高效稳定运转目标同时也易于未来扩展.
126 8
|
3月前
|
Java Spring
如何优化Java异步任务的性能?
本文介绍了Java中四种异步任务实现方式:基础Thread、线程池、CompletableFuture及虚拟线程。涵盖多场景代码示例,展示从简单异步到复杂流程编排的演进,适用于不同版本与业务需求,助你掌握高效并发编程实践。(239字)
234 6
|
3月前
|
数据采集 存储 弹性计算
高并发Java爬虫的瓶颈分析与动态线程优化方案
高并发Java爬虫的瓶颈分析与动态线程优化方案
|
3月前
|
缓存 Java 开发者
Java 开发者必看!ArrayList 和 LinkedList 的性能厮杀:选错一次,代码慢成蜗牛
本文深入解析了 Java 中 ArrayList 和 LinkedList 的性能差异,揭示了它们在不同操作下的表现。通过对比随机访问、插入、删除等操作的效率,指出 ArrayList 在多数场景下更高效,而 LinkedList 仅在特定情况下表现优异。文章强调选择合适容器对程序性能的重要性,并提供了实用的选择法则。
194 3