在知道有必要之前不要急于优化使用分析器找到真正的瓶颈为您的整个应用程序创建性能测试套件首先关注最大的瓶颈以编程方式连接与StringBuilderStrings尽可能使用原始类型避免大整数和小数使用ApacheCommonsStringUtils.Replace而不是String.replace数据库连接等昂贵的缓存资源大多数开发人员认为性能优化是一个复杂的主题,需要大量的工作经验和相关知识论。好吧,这并不完全错误。优化应用程序以获得最佳性能可能不是一件容易的事,但这并不意味着您不能在不了解的情况下做任何事情。以下是一些易于遵循的建议和最佳实践,可帮助您创建性能良好的应用程序。这些建议中的大多数都是特定于Java语言的。但也有一些是独立于语言的,你可以应用于任何应用程序和程序。在我们研究具体的Java编程性能调优之前,让我们探索一些通用技术。1.在知道有必要之前不要优化这可能是最重要的性能优化技术之一。您应该遵循常见的最佳实践并将其有效地应用到您的案例中。但这并不意味着您应该替换任何标准库或构建复杂的优化,直到证明有必要为止。在大多数情况下,过早的优化会花费大量时间并使代码难以理解和阅读。更糟糕的是,这些优化通常不会带来任何好处,因为您花费大量时间优化应用程序的非关键部分。那么,你如何证明某些东西需要优化呢?首先,您需要定义代码的速度。例如,指定所有API调用的最大响应时间,或指定在某个时间范围内导入的记录数。完成此操作后,您需要确定应用程序的哪些部分运行缓慢且需要改进。完成后,您可以转到第二个提示。2.使用分析器找到真正的瓶颈在完成第一部分中的优化建议以确定您的应用程序需要改进的部分之后,您从哪里开始呢?您可以通过两种方式解决此问题:查看您的代码,从看起来可疑或您认为可能会导致问题的内容开始。或者使用分析器来获取有关代码每个部分的行为(执行过程)和性能的详细信息。希望我不需要解释为什么应该始终遵循第二条路线/方法。显然,基于分析器的方法可以让您更好地了解代码的性能影响,并让您专注于更关键的部分(代码)。即使您曾经使用过性能分析器,您也会记得您是多么惊讶地发现您的代码的哪些部分导致了一次单击的性能问题。我的第一个猜测不止一次把我引向了错误的方向。3.为整个应用程序创建性能测试套件这是另一种通用技术,可以帮助您避免在将性能改进部署到生产环境后经常发生的许多意外问题。您应该始终定义一个性能测试套件来测试整个应用程序,并在性能改进前后运行它。这些额外的测试运行将帮助您识别由更改引起的功能和性能副作用,并确保它们不会导致弊大于利的更新。如果您要处理由应用程序的多个不同部分使用的组件(例如数据库或缓存),这一点尤其重要。4.确定最大瓶颈的优先级在创建测试套件并使用分析器分析应用程序之后,您可以列出需要解决以提高性能的问题列表。这很好,但它没有回答您需要从哪里开始的问题。您可以专注于快速修复,或从最重要的问题开始。速成计划起初可能很有吸引力,因为您可以非常快速地显示初步结果。但有时,可能有必要说服其他团队成员或管理层相信分析是值得的。一般来说,我建议从顶层开始,首先从最重要的性能问题开始。这将为您带来最大的性能改进,并且您可能只需要解决这些问题中的一小部分即可满足您的性能要求。这总结了通常的一般调整技巧。让我们仔细看看一些特定于Java的技巧。5.使用StringBuilder以编程方式连接字符串在Java中连接字符串有许多不同的选项。例如,您可以使用简单的+或+=,以及旧的StringBuffer或StringBuilder。那么,您应该选择哪种方法呢?答案取决于连接字符串的代码。如果您以编程方式向字符串添加新内容,例如在for循环中,您应该使用StringBuilder。它易于使用并提供比StringBuffer更好的性能。但请记住,与StringBuffer相比,StringBuilder不是线程安全的,可能并不适合所有情况。您只需要实例化一个新的StringBuilder并调用append方法将新的部分添加到String中。添加所有部分后,您可以调用toString()方法来检索串联的字符串。下面的代码片段显示了一个简单的示例。在每次迭代期间,循环将i转换为String并将其与空格一起添加到StringBuildersb中。所以,最后,这段代码在日志文件中写入“Thisisatest0123456789”。StringBuildersb=newStringBuilder("Thisatest");for(inti=0;i<10;i++){sb.append(i);sb.append("");}log.info(sb.toString());正如您在代码片段中看到的那样。我们可以将字符串的第一个元素提供给构造函数。这将创建一个StringBuilder,其中包含您提供的字符串以及16个额外字符的容量。当您向StringBuilder添加更多字符时,您的JVM将动态增加StringBuilder的大小。如果您已经知道字符串将包含多少个字符,则可以将该数字提供给各种构造函数方法,以实例化具有指定容量的StringBuilder。这进一步提高了效率,因为它不需要动态扩展其容量。6.尽可能使用原始类型另一种避免任何开销并提高应用程序性能的简单快捷的方法是使用原始类型而不是它们的包装类。因此,最好使用int而不是Integer和double而不是Double。这将使你的JVM将值存储在堆栈而不是堆上,以减少内存消耗并更有效地处理它。7.尽量避免大整数和小数既然我们已经讨论了数据类型,我们也应该快速看一下大整数和小数。后者尤其因其精确性而广受欢迎。但这是有代价的。大整数和小数比简单的long或double需要更多的内存,并且会显着减慢所有操作。因此,如果您需要更高的精度,或者如果您的数字超出了很长的范围,最好三思而后行。这可能是您唯一需要更改和修复性能问题的东西,尤其是在实现数学算法时。8.使用ApacheCommonsStringUtils.Replace而不是String.replace通常,String.replace方法工作正常并且非常高效,尤其是在使用Java9时。但是,如果您的应用程序需要大量替换操作并且您还没有更新到最新的Java版本,那么仍然值得检查更快、更高效的替代方案。一个候选者是ApacheCommonsLang的StringUtils.replace方法。正如LukasEder在他最近的博客文章中所描述的那样,它远远优于Java8的String.replace方法。而且它只需要很小的改动。您只需要将ApacheCommonsLang项目的Maven依赖项添加到应用程序的pom.xml中,并将String.replacemethod的所有调用替换为StringUtils.replace方法。//replacethistest.replace("test","simpletest");//withthisStringUtils.replace(test,"test","simpletest");9.昂贵的缓存资源,例如数据库连接缓存,是昂贵的或者常用的避免重复执行代码片段的流行解决方案。总体思路很简单:重用这些资源比创建新资源更具成本效益。一个典型的例子是在池中缓存数据库连接。创建新连接需要时间,如果您重用现有连接,则可以避免这种情况。您还可以在Java语言源代码中找到其他示例。例如,Integer类中的valueOf方法缓存介于-128和127之间的值。您可能会争辩说创建一个新的Integer并不太昂贵,但由于它经常被使用,缓存最常用的值也可以提供性能优势。但是,当您考虑缓存时,请记住缓存实现也有开销。您需要花费额外的内存来存储可重复使用的资源,因此您可能需要管理缓存以使资源可访问并删除过期资源。因此,在开始缓存任何资源之前,请确保它们被频繁使用以超过缓存实现的开销(成本)。总结如您所见,有时不需要做太多工作就可以提高应用程序的性能。本文中的大部分建议只需要一点点努力就可以应用到您的代码中。但同样,最重要的是与语言无关的提示:在知道有必要之前不要进行优化使用分析器找到真正的瓶颈确定最大瓶颈的优先级来源:DZonehttp://sina.lt/gnWz
