10个简单的 Java 性能调优技巧

  优化应用程序以获得最佳性能不是一件容易的事情。但是,这并不意味着如果你不具备这些知识,就不能做任何事情。这里有11个易于遵循的建议和最佳实践可以帮助你创建一个性能良好的应用程序。

大部分建议是针对Java的。但也有若干建议是与语言无关的,可以应用于所有应用程序和编程语言。在讨论专门针对Java的性能调优技巧之前,让我们先来看看通用技巧。

1.在你知道必要之前不要优化

这可能是最重要的性能调整技巧之一。你应该遵循常见的最佳实践做法并尝试高效地实现用例。但是,这并不意味着在你证明必要之前,你应该更换任何标准库或构建复杂的优化。

在大多数情况下,过早优化不但会占用大量时间,而且会使代码变得难以阅读和维护。更糟糕的是,这些优化通常不会带来任何好处,因为你花费大量时间来优化的是应用程序的非关键部分。

那么,你如何证明你需要优化一些东西呢?

首先,你需要定义应用程序代码的速度得多快,例如,为所有API调用指定最大响应时间,或者指定在特定时间范围内要导入的记录数量。在完成这些之后,你就可以测量应用程序的哪些部分太慢需要改进。然后,接着看第二个技巧。

2.使用分析器查找真正的瓶颈

在你遵循第一个建议并确定了应用程序的某些部分需要改进后,那么从哪里开始呢?

你可以用两种方法来解决问题:

  • 查看你的代码,并从看起来可疑或者你觉得可能会产生问题的部分开始。
  • 或者使用分析器并获取有关代码每个部分的行为和性能的详细信息。

希望不需要我解释为什么应该始终遵循第二种方法的原因。

很明显,基于分析器的方法可以让你更好地理解代码的性能影响,并使你能够专注于最关键的部分。如果你曾使用过分析器,那么你一定记得曾经你是多么惊讶于一下就找到了代码的哪些部分产生了性能问题。老实说,我第一次的猜测不止一次地导致我走错了方向。

3.为整个应用程序创建性能测试套件

这是另一个通用技巧,可以帮助你避免在将性能改进部署到生产后经常会发生的许多意外问题。你应该总是定义一个测试整个应用程序的性能测试套件,并在性能改进之前和之后运行它。

这些额外的测试运行将帮助你识别更改的功能和性能副作用,并确保不会导致弊大于利的更新。如果你工作于被应用程序若干不同部分使用的组件,如数据库或缓存,那么这一点就尤其重要。

4.首先处理最大的瓶颈

在创建测试套件并使用分析器分析应用程序之后,你可以列出一系列需要解决以提高性能的问题。这很好,但它仍然不能回答你应该从哪里开始的问题。你可以专注于速效方案,或从最重要的问题开始。

速效方案一开始可能会很有吸引力,因为你可以很快显示第一个成果。但有时,可能需要你说服其他团队成员或管理层认为性能分析是值得的——因为暂时看不到效果。

但总的来说,我建议首先处理最重要的性能问题。这将为你提供最大的性能改进,而且可能再也不需要去解决其中一些为了满足性能需求的问题。

常见的性能调整技巧到此结束。下面让我们仔细看看一些特定于Java的技巧。

5.使用StringBuilder以编程方式连接String

有很多不同的选项来连接Java中的String。例如,你可以使用简单的+或+ =,以及StringBuffer或StringBuilder。

那么,你应该选择哪种方法?

答案取决于连接String的代码。如果你是以编程方式添加新内容到String中,例如在for循环中,那么你应该使用StringBuilder。它很容易使用,并提供比StringBuffer更好的性能。但请记住,与StringBuffer相比,StringBuilder不是线程安全的,可能不适合所有用例。

你只需要实例化一个新的StringBuilder并调用append方法来向String中添加一个新的部分。在你添加了所有的部分之后,你就可以调用toString()方法来检索连接的String。

下面的代码片段显示了一个简单的例子。在每次迭代期间,这个循环将i转换为一个String,并将它与一个空格一起添加到StringBuilder sb中。所以,最后,这段代码将在日志文件中写入“This is a test0 1 2 3 4 5 6 7 8 9”。

StringBuilder sb = new StringBuilder(“This is a test”);
for (int i=0; i<10; i++) {sb.append(i);sb.append(” “);
}
log.info(sb.toString());

正如在代码片段中看到的那样,你可以将String的第一个元素提供给构造方法。这将创建一个新的StringBuilder,新的StringBuilder包含提供的String和16个额外字符的容量。当你向StringBuilder添加更多字符时,JVM将动态增加StringBuilder的大小。

如果你已经知道你的String将包含多少个字符,则可以将该数字提供给不同的构造方法以实例化具有定义容量的StringBuilder。这进一步提高了效率,因为它不需要动态扩展其容量。

6.使用+连接一个语句中的String

当你用Java实现你的第一个应用程序时,可能有人告诉过你不应该用+来连接String。如果你是在应用程序逻辑中连接字符串,这是正确的。字符串是不可变的,每个字符串的连接结果都存储在一个新的String对象中。这需要额外的内存,会减慢你的应用程序,特别是如果你在一个循环内连接多个字符串的话。

在这些情况下,你应该遵循技巧5并使用StringBuilder。

但是,如果你只是将字符串分成多行来改善代码的可读性,那情况就不一样了。

Query q = em.createQuery(“SELECT a.id, a.firstName, a.lastName ”
+ “FROM Author a ”
+ “WHERE a.id = :id”);

在这些情况下,你应该用一个简单的+来连接你的字符串。Java编译器会对此优化并在编译时执行连接。所以,在运行时,你的代码将只使用1个String,不需要连接。

7.尽可能使用基元

避免任何开销并提高应用程序性能的另一个简便而快速的方法是使用基本类型而不是其包装类。所以,最好使用int来代替Integer,使用double来代替Double。这允许JVM将值存储在堆栈而不是堆中以减少内存消耗,并作出更有效的处理。

8.试着避免BigInteger和BigDecimal

既然我们在讨论数据类型,那么我们也快速浏览一下BigInteger和BigDecimal吧。尤其是后者因其精确性而受到大家的欢迎。但是这是有代价的。

BigInteger和BigDecimal比简单的long或double需要更多的内存,并且会显著减慢所有计算。所以,你如果需要额外的精度,或者数字将超过long的范围,那么最好三思而后行。这可能是你需要更改以解决性能问题的唯一方法,特别是在实现数学算法的时候。

9.首先检查当前日志级别

这个建议应该是显而易见的,但不幸的是,很多程序员在写代码的时候都会大多会忽略它。在你创建调试消息之前,始终应该首先检查当前日志级别。否则,你可能会创建一个之后会被忽略的日志消息字符串。

这里有两个反面例子。

// don’t do this
log.debug(“User [” + userName + “] called method X with [” + i + “]”);
// or this
log.debug(String.format(“User [%s] called method X with [%d]”, userName, i));

在上面两种情况中,你都将执行创建日志消息所有必需的步骤,在不知道日志框架是否将使用日志消息的前提下。因此在创建调试消息之前,最好先检查当前的日志级别。

// do this
if (log.isDebugEnabled()) {log.debug(“User [” + userName + “] called method X with [” + i + “]”);
}

10.使用Apache Commons StringUtils.Replace而不是String.replace

一般来说,String.replace方法工作正常,效率很高,尤其是在使用Java 9的情况下。但是,如果你的应用程序需要大量的替换操作,并且没有更新到最新的Java版本,那么我们依然有必要查找更快和更有效的替代品。

有一个备选答案是Apache Commons Lang的StringUtils.replace方法。正如Lukas Eder在他最近的一篇博客文章中所描述的,StringUtils.replace方法远胜Java 8的String.replace方法。

而且它只需要很小的改动。即添加Apache Commons Lang项目的Maven依赖项到应用程序pom.xml中,并将String.replace方法的所有调用替换为StringUtils.replace方法。

// replace this
test.replace(“test”, “simple test”);
// with this
StringUtils.replace(test, “test”, “simple test”);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/503269.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

服务器linux启动,Linux 服务器环境启动

1、PHP关闭phpkillall php-fpmphp重启/usr/local/php/sbin/php-fpm &或者/usr/local/php/sbin/php-fpm {start|stop|quit|restart|reload|logrotate}--start 启动php的fastcgi进程--stop 强制终止php的fastcgi进程--quit 平滑终止php的fastcgi进程--restart 重启php的fastc…

浅谈Spring注解

Spring目前的趋势是使用注解结合Java代码而不是配置来定义行为、属性、功能、规则和扩展点&#xff0c;因此梳理注解也是梳理Spring功能点的很好的方式&#xff0c;全面的梳理可以补足我们知识点的漏洞。 查找所有注解 首先&#xff0c;我们来创建一个项目&#xff0c;使用SP…

linux nginx 状态,Nginx开启运行状态(status)功能 | IT运维网

1、查验Nginx的Status模块,此模块一般安装时都会安装的。2、编辑Nginx主配置文件(/usr/local/nginx/conf/nginx.conf)在默认站点中配置Status功能location /nginx_status #开启Nginx站点运行状态功能并定义状态查看访问位置{stub_status on; #启用状态access_log…

Java 并发编程必须知道的七种锁类型以及应用

锁是解决并发冲突的重要工具。在开发中我们会用到很多类型的锁&#xff0c;每种锁都有其自身的特点和适用范围。 需要深刻理解锁的理念和区别&#xff0c;才能正确、合理地使用锁。 常用锁类型 乐观锁与悲观锁 悲观锁对并发冲突持悲观态度&#xff0c;先取锁后访问数据&…

linux原理与应用期末考试,武汉大学计算机学院2009-2010学年第一学期期末考试《Linux原理与应用》期末考试试卷(共8套,有答案)...

内容简介&#xff1a;Linux 期末考试试题(共8套&#xff0c;有答案)Linux 期末考试试题(一)一、选择题 (每小题2分&#xff0c;共50分)1.在创建Linux分区时&#xff0c;一定要创建( D )两个分区A. FAT/NTFS B. FAT/SWAP C. NTFS/SWAP D.SWAP/根分区2.在Red Hat Linux 9中&#…

linux kvm dhcp配置,《转》QEMU-KVM创建虚拟机自动指定IP的配置

在使用qemu创建虚拟机的过程中是无法指定IP地址的&#xff0c;可是在实际应用中&#xff0c;我们是需要虚拟机拥有IP地址的&#xff0c;并且不是人为去虚拟机操作系统上配置。在qemu虚拟机技术文档(http://qemu.weilnetz.de/qemu-doc.html#pcsys_005fmonitor)里捣鼓了好久&…

谈一谈Java编程开发中的并发控制

并发指在宏观上的同一时间内同时执行多个任务。为了满足这一需求&#xff0c;现代的操作系统都抽象出 线程 的概念&#xff0c;供上层应用使用。 这篇博文不打算详细展开分析&#xff0c;而是对java并发中的概念和工具做一个梳理。 沿着并发模型、并发要解决的问题、基本工具、…

c语言中头文件及其作用,C语言头文件的作用是什么

C语言头文件的作用&#xff1a;1、头文件是程序各部分之间保证信息一致性的桥梁&#xff0c;是连接程序对象定义和使用的纽带&#xff1b;2、用于指定模块接口的声明放在文件中&#xff0c;文件名中应标明其预期用途。本文操作环境&#xff1a;Windows7系统&#xff0c;宏基S40…

Java技术大咖为什么都有写博客的习惯呢?

把自己的设计、思路、总结都写到日记里&#xff08;我用evernote&#xff09;&#xff0c;便于自己思路的整理&#xff0c;很多时候人脑的缓存是真不够用&#xff0c;后面回来找思路的时候&#xff0c;细节也都在笔记里面。 1.让我思维更清晰&#xff0c;表述更有条理 我生活中…

奥鹏20年12月作业考核(C语言专科),《C语言(专科)》20年12月作业考核【答案100分】...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼《C语言(专科)》20年12月作业考核共20道题 总分&#xff1a;100分100分咨询dddda98咨询dddda98咨询dddda98单选题一、单选题共20题&#xff0c;100分15分请选出可用作C语言用户标识符的一组标识符( )Avoid define WORDBa3_b3 _123 …

Java与C++有何区别呢?请看以下几点就明白了……

Java和C都是面向对象语言。也就是说&#xff0c;它们都能够实现面向对象思想。那两者到底有何区别&#xff1f;由于c为了照顾大量的C语言使用者&#xff0c; 而兼容了C&#xff0c;使得自身仅仅成为了带类的C语言&#xff0c;多多少少影响了其面向对象的彻底性&#xff01;JAVA…

零基础学习java必须要了解的学习路线

Java开发目前热火朝天&#xff0c;但是有传言说Java将被取代&#xff0c;当然那只是传言。今天小编来谈谈零基础学习Java必须了解的学习路线。 第一阶段&#xff1a;HTMLCSS 静态布局开始 有人肯能会说我是做后端的&#xff0c;前端的事情不用管&#xff0c;这本身就是一个误区…

linux相关英文书记,Linux常用软件(英文介绍)

Linux常用软件(英文介绍)发布时间:2007-09-27 15:37:36来源:红联作者:wsecurotyFirefoxThe best internet browserAmaroKThe most sophisticated mp3 player for Linuxk3bK3b is a feature-rich and easy to handle CD burning application.ThunderbirdThe best email clientba…

linux openoffice centos,centos8 openoffice安装

安装桌面GUIyum check-updateyum -y install lvm2 device-mapperyum -y groupinstall GNOME1. 首先下载rpm包下载rpm包(官网或者其他网站都可以)但是要注意版本,我建议是4.1.2版本以上,因为以前的版本不支持含有中文的文件名的文档转pdf;我下载的是这个Apache_OpenOffice_4.1.3…

Java开发以及Web 和移动程序员必须了解的10个框架

新的一年已经开始&#xff0c;不知道大家有没有定好小目标。如果2019年还没有决定学什么&#xff0c;那么你来对地方了。在今天的文章中&#xff0c;我将分享一些你可以学习的最好框架&#xff0c;以提升你在移动和Web开发以及大数据技术方面的知识。 在当今世界&#xff0c;对…

c语言在机械专业的应用,高职院校机械类C语言程序设计教学改革探讨

摘 要&#xff1a;C语言程序设计作为高职院校机械类专业公共课程&#xff0c;对于培养学生快速掌握计算机程序设计的能力&#xff0c;更快地适应后续专业课程的学习是很重要的。所以就需要本课程老师能按照本门课程的定位以及机械类专业的需求&#xff0c;较好的实施教学内容的…

Java开发学习必须了解的基础知识点

面向对象和面向过程的区别 面向过程&#xff1a; 优点&#xff1a;性能比面向对象高&#xff0c;因为类调用时需要实例化&#xff0c;开销比较大&#xff0c;比较消耗资源;比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发&#xff0c;性能是最重要的因素。 缺点&a…

电子琴仿真c语言程序,矩阵键盘模拟电子琴C语言程序设计

原标题&#xff1a;矩阵键盘模拟电子琴C语言程序设计//24c08地址为0xa0#include #define uchar unsigned charunsigned char code table[]{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};unsigned char sec0; //定义计数值,每过1秒,sec加1unsigned int count; //定时中断…

Java的数据类型及其封装器类

Java基本类型共有8种&#xff0c;基本类型可以分为3类&#xff0c;字符类型char&#xff0c;布尔类型boolean和数值类型byte、short、int、long、float、double。数值类型又可以分为整数类型byte、short、int、long和浮点数类型float、double。JAVA中的数值类型不存在无符号的&…

c语言字符为0和1,//C语言:将一个由字符0和1组成的表示二进制数的字符串,转换成相应的十进制数返回。...

//函数fun:将一个由字符0和1组成的表示二进制数的字符串&#xff0c;转换成相应的十进制数返回。#include #pragma warning (disable:4996)#define N 16/**********************found***********************/int fun( char s[]) //形参不要使用定值{ int i, n ;/************…