原文出自:http://blog.csdn.net/anxpp/article/details/51914119,转载请注明出处,谢谢!

1、前言

OK,之前写了一篇文章:“23种设计模式介绍以及在Java中的应用”详细介绍了如何将设计模式应用到Java编程中,而本文旨在介绍如何利用他们优化我们的程序,使其性能更佳。

设计模式的详细介绍请参照上面链接中的文章,不是本文的重点。

而Java程序的性能优化,不一定就仅仅是以提高系统性能为目的的,还可能是以用户体验、系统可维护性等为目的。

2、概述

我们知道,设计模式能够大大的优化我们的代码,是针对某一类问题的最优解决方案,是从许多优秀的软件系统中总结出的。

本文重点是Java程序性能优化中的设计优化,介绍的设计模式都是与性能相关的。

出了设计模式,文章也会介绍一些相关的设计组件和设计方法。

3、合理使用设计模式

该节中涉及的设计模式,都在文首链接的文章中详细的介绍了,如果不清楚他们的实现,请先阅读它们。

3.1、单例模式

单例模式最容易理解,也最常见,是一种对象创建模式。

下面是一种简单但正确的实现方式:

  1. public enum EasySingleton{
  2. INSTANCE;
  3. }

    上面的方式实现代理,利用的是Java自有的机制,线程是安全的,也不担心被使用反射强行调用构造方式产生多个实例。

    在Java语言中,单例模式能明显带来的好处:

    1、对于频繁使用的对象,可以省略创建对象所花费的时间,这对于那些重量级的对象来说,尤为明显。

    2、由于没有new更多的对象,内存使用频率也降低,从而减轻GC(垃圾回收器)的压力。

    不过单例模式切不可滥用,不然很容易造成内存泄露,可参考:JAVA 内存泄露详解

    3.2、代理模式

    代理模式也很常用,可以屏蔽用户对真实对象的访问。

    而且代理模式还能简单的实现AOP(面向切面编程)。

    但是涉及到性能的,主要是体现在使用代理模式实现延迟加载。延迟加载的核心思想是:如果当前没有使用这个对象(或组件),就不需要真正的创建它。

    3.2.1、简单示例

    下面还是要看一个简单的示例:

  1. package com.anxpp.hello911.proxy;
  2. //使用
  3. public class SimpleProxy {
  4. public static void main(String[] args) {
  5. IBase base = new BaseProxy(); //使用代理
  6. base.doSomeThing(); //使用时懒加载
  7. }
  8. }
  9. interface IBase{
  10. String doSomeThing();
  11. }
  12. //类本身,通常是重量级的对象
  13. class Base implements IBase{
  14. public Base() {
  15. try {
  16. //构造这个对象可能是非常耗时的操作
  17. Thread.sleep(2000);
  18. } catch (InterruptedException e) {
  19. e.printStackTrace();
  20. }
  21. }
  22. @Override
  23. public String doSomeThing() {
  24. return "result";
  25. }
  26. }
  27. //代理类
  28. class BaseProxy implements IBase{
  29. private IBase base = null;
  30. @Override
  31. public String doSomeThing() {
  32. if(base==null)
  33. base = new Base();
  34. return base.doSomeThing();
  35. }
  36. }

    当我们要使用的对象是一个相对重量级的时候,我们可以使用上面的代理模式,为这个对象作懒加载。

    为什么会优化性能呢?这是对用户而言,因为对象是懒加载的,比如,系统启动速度会有效(基于这个对象的构造复杂度)提升,因此会很好的改善用户的体验。再者,有些组件,可能再程序的生命周期并不一定会被调用,而使用懒加载,无疑就避免了这些资源的浪费。

    3.2.2、动态代理

    动态代理是在运行时,动态的生成代理类。

    如果类本身实现的接口中包含了较多的方法,那么,为每个接口都实现一个代理类,是比较繁琐的。 如果接口发生改变,真是对象和代理对象都要修改。但是若使用代理模式生成方法,将大大优化上面出现的问题。

    3.3、享元模式

    享元模式的主要目的就是提高系统性能,就是真正意思上的性能优化了。

    享元模式的最佳实践之一,就是Java中的String类了,相信大家也是非常清楚的。

    其核心原理:如果系统中存在多个相同的对象,那么只需要共享一分对象的拷贝。

    对性能的提升主要体现在两点:

    1、节约重复创建对象的开销。

    2、减小系统内存的开销。

    3.4、装饰者模式

    装饰者模式巧妙的设计结构:可以动态的为对象添加功能。

    根据“合成/聚合”复用原则,代码复用应该尽可能使用委托(即组合),而不是继承,因为继承是一种紧耦合的,父类的任何改动都会影响其子类,不利于系统维护。但是委托使松耦合的,只要接口不变,委托类的改动并不会影响其上层对象。

    装饰者模式可以有效的分离性能组件和功能组件,从而提升模块的可维护性并增加模块的复用性。

    具体实现请参考文首的文章链接中的相关内容。

    3.5、观察者模式

    观察者模式也是一种比较常用的设计模式。

    系统中的一个对象的行为依赖另一个对象时,观察者模式就相当有用。

    如果在常规方法中,需要实现类似功能的话,需要开启多个线程监控所依赖的对象的状态(多线程实际上是会加重系统的负担的),但是入股欧使用观察者模式,实现这样的功能可以在单线程中完成。

    观察者模式可以用于时间的监听、通知发布等场合,可以确保将这个变化通知给观察者。

    JDK中也实现了一套观察者模式,详见文首链接的文章。

    3.6、Value Object模式

    Value Object是一种什么样的模式呢?其实就是将一组操作原子化。

    比如,如果我们要从数据库取得一组特定的结果,他们可能需要经过多次查询或者还需要计算,那么如果仅仅是在Java代码中经过多次查询并组织成我们的目标结果,可能并不是一个好的设计。相反,我们可以将这些属性,封装到一个对象中,然后使用存储过程(Oracle也直接导入Java代码来代替存储过程,如果数据需要经过大量的计算处理,这将比存储过程效率高很多)将这些操作原子化,大大减少数据库访问次数,就能达到系统优化的目的。

    而这种模式的应用不仅仅上上面这点,比如我们前端访问服务器取得数据,需要经过多次取值再组合显示的话,我们完全可以将这些属性封装到一个对象中,同意处理后返回,会减少服务器访问次数(不过如果需要懒加载,就需要分步获取数据)。

    3.7、业务代理模式

    业务代理模式可能概念上有点近似Value Object模式,不过它封装的不是一系列操作的属性,而是将部分业务流程组合到一起。

    我们也可以将其与模板方法做对比,他们都是将一系列操作组合到一起。

    业务代理模式将一些业务流程封装在前台系统,为系统性能优化提供了基础平台。


4、组件和方法

    4.1、缓冲(Buffer)

    缓冲区是一块专门用于化解程序中各个模块(或者层次)间的性能差异的,可以提高系统性能。

    使用的地方也很多,比如我们要将接收到的数据保存到硬盘中,从网络I/O中读取的数据是不稳定的,可能会很快,但是写入数据到硬盘的速度基本是固定的,两者是有差异的。我们可以通过在内存中开辟一块用来缓存数据,然后按一定的机制统一写到硬盘中,以协调两者的速度不匹配问题。这时候,如果从网络来的数据比较集中,也不用等数据都写入带硬盘后再继续接收剩余的数据,相反,如果网络I/O的数据很少,也可以先放到缓冲中,等到数据量达到一定程度后再统一写入硬盘。

    缓冲可以协调上层组件和下层组件的性能差异。当上层组件性能优于下层组件时,可以有效减少上层组件对下层组件的等待时间。

    由于I/O操作很容易成为性能瓶颈,所以尽可能在I/O读写中加入缓冲组件,以提高性能。

    4.2、缓存(Cache)

    缓存也是一块内存中专门开启的空间,主要是缓存数据处理结果,并提供给下一次访问。

    比如我们查询数据库的结果,如果没有修改数据库中的数据,那么每次查询的结果应该是一样的,我们没必要就每次要去查询一次,直接将结果缓存到内存中,下次需要的时候直接从内存中取即可。

    缓存的使用场合非常多,所以现在也有很多流行的支持缓存的NoSQL数据库,比如Redis。

    目前也有很多缓存使用相关的框架,不仅可以缓存数据到本地,还可以缓存到远程分布式缓存服务器中。

    缓存可以保存一下来之不易的数据或计算结果。当需要再次使用这些数据时,可以从缓存中低成本的获取。

    4.3、池

    对象池化也是一个非常常用的系统优化技术。

    核心思想是:如果一个类被频繁请求使用,那么不必每次都生成一个示例,可以将这个类的一些实例保存在一个“池”中,待需要使用时,直接从池中获取。

    实现上,它可以是数组、链表等任何集合。

    可能使用最多的就是线程池,线程池中保存的就是可以被重用的线程对象,当任务呗提交到线程池时,系统并不一定需要新建线程,而是从池中获取一个可用的线程来执行这个任务。

    在程序中使用数据库连接池和线程池,可以有效的改善系统咋高并发下的性能。而目前可能对数据库操作都常使用一些ORM框架,它们都很好的封装了数据库连接池,可能碰到更多的,还是线程池。当然,其他类似的情况,我们也可以考虑自己实现一个池。

    4.4、并行而不是串行

     也就是多线程技术,它可以将CPU的潜能发挥到最大化。

    并发相关技术请参考博客总并发相关的文章。

    4.5、负载均衡

    对于一些大型应用,单台服务器是无法满足需求的,可能就需要部署多台作集群,然后使用负载均衡技术将工作尽可能的平均分配到各个服务器上。

    比如一个Web服务器,如果较高的并发已经导致系统频繁的无响应等,通常就会配置多台服务器集群,然后使用Nginx等应用作负载均衡,将请求分配到不同的服务器上。而Session的管理,可能就会使用诸如Redis等缓存数据库,统一管理。

    4.6、时间与空间之间的权衡

    对于不同的业务类型,可能对时间(CPU)和空间(存储)的需求也各不相同。

    性能的优化在于掌握各部分组件的性能平衡点。如果系统CPU资源有空闲,但是内存使用紧张,便可以考虑使用时间换空间的策略,大道整体性能的改进。相反,如果CPU资源紧张,就可以考虑用空间换时间。

    在很多算法(比如常见的排序算法),他们对的时间复杂度和空间复杂度是各不相同的,在使用时没应考虑时间和空间的权衡。


5、总结

    本文主要是探讨在设计上如何优化我们的程序,而优化并不一定就完全是提高系统的性能,还可能是用户体验、可维护性等。

Java程序性能优化——设计优化相关推荐

  1. java程序性能优化(实例)

    java程序性能优化(实例) 一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: i ...

  2. Java程序性能优化——性能调优层次

    为了提升系统性能,开发人员可以从系统的各个角度和层次对系统进行优化.除了最常见的代码优化外,在软件架构上.JVM虚拟机层.数据库以及操作系统层都可以通过各种手段进行调优,从而在整体上提升系统的性能. ...

  3. Java程序性能优化 读书笔记(十)并行设计模式:Future模式

    转载:Java多线程编程中Future模式的详解<转> 参考:葛一鸣,Java程序性能优化.清华大学出版社. 随着多核时代的到来,CPU的并行能力有了很大的提升.在这种背景下,传统的串行程 ...

  4. 滴滴架构师被迫离职后,只留下这份731页Java程序性能优化手册

    滴滴资深架构师深度分享Java程序性能优化的宝贵经验,从软件设计.编码和JVM等维度阐述性能优化的方法和技巧. 总览: 篇幅限制,这里就不全部展示出来了.需要获取完整版Java程序性能优化手册的小伙伴 ...

  5. Java 程序性能优化《第一章》Java性能调优概述 1.4小结

    Java 程序性能优化<第一章>1.4小结 通过本章的学习,读者应该了解性能的基本概念及其常用的参考指标.此外,本章还较为详细的介绍了与性能调优相关的两个重要理论--木桶原理以及Amdah ...

  6. Java程序性能优化-概述

    前言     这两天在看<Java程序性能优化>这本书,将我学到的书上好的东西分享给大家.做过开发的人应该或多或少都碰到过性能问题,遇到性能问题你是怎么做的呢?你能看懂程序的性能吗?本篇给 ...

  7. 开源即巅峰,《Java程序性能优化实战》GitHub三小时标星已超34k

    蓦然回首自己做开发已经十年了,这十年中我获得了很多,技术能力.培训.出国.大公司的经历,还有很多很好的朋友.但再仔细一想,这十年中我至少浪费了五年时间,这五年可以足够让自己成长为一个优秀的程序员,可惜 ...

  8. java程序性能优化(一)

    根据<java程序性能优化>整理 字符串的分割和查找,在日常编码中很常见,平时使用最多的split()函数,但是也有一些更优的选择,下面就让我来一一对比: 上面的这个就是常用的split( ...

  9. java 复杂网络分析_基于复杂网络的Java程序分析工具设计与实现思路浅谈

    基于复杂网络的Java程序分析工具设计与 实现思路浅谈 摘要:近年来,随着科学技术的进步,计算机技术发展速度的加快,使得软件价值也逐步提高,不管是软件系统的应用领域,还是其规模均获得了相应的扩大,且软 ...

最新文章

  1. 基于form的身份验证怎样设置一个特例(使某页不需要验证)
  2. springMVC图片的上传与下载
  3. 域服务器可以修改ip,Windows Server 2016 域控制器修改IP
  4. fedora下安装pps
  5. java 标准输入流 关闭 打开_java--标准输入输出流
  6. Ubuntu16.04下安装cuda和cudnn的三种方法(亲测全部有效)
  7. tomcat日志,用户以及启动时的一些问题
  8. 计算机应用作业2,计算机应用2作业
  9. windows2008开机占用多少内存_如何提升电脑开机速度?
  10. 每秒上百万次的跨数据中心写操作,Uber是如何使用Cassandra处理的?
  11. 110kV终端变电站电气部分设计
  12. Ubuntu16.04关机后自动重启解决方案
  13. 数据模型的作用和数据模型的三个要素:
  14. 智慧海洋task04 利用数据进行建模并调参
  15. GNN从入门到精通 -- Graph Embedding (2)
  16. windows server 2003 IE升级方法
  17. Kaldi-Timit 训练
  18. ubuntu中截图工具shutter编辑按钮不可用
  19. 三阶魔方CFOP复原的C语言算法
  20. 移动运营商AIS泄漏了83亿条用户数据 容量约4.7 TB

热门文章

  1. webERP 添加客户-amp;gt;分公司信息 'vtiger_accountid' doesn't have a default value
  2. 浅谈计算机网络及交换机基础配置
  3. LabVIEW图形化TensoRT工具包的安装下载分享
  4. 基于Android的旅游app的设计与实现
  5. 【机器学习】逻辑回归(LogisticRegression)原理与实战
  6. 搜图出处的软件_【识图】怎样查找图片的来源出处,又快又好
  7. JavaScript jQuery遍历对象each()方法
  8. Spring知识点记录
  9. 活动运营中如何准确把握用户心理
  10. d2的自定义训练和增强