J2EE系统优化:对象与循环
优化一般意义上说是提高已有系统的性能,减少如内存、数据库、网络带宽等资源的占用,是在系统开发告一段落的前提下进行。一般是通过压力测试或具体使用发现性能方面的问题,然后寻找性能瓶颈,并结合项目进度、人员安排、技术储备等因素,提出相应的优化策略。
下面结合一些案例,进行具体的讨论,总结出两个有代表性的条例:
条例一:尽量重用对象,避免创建过多短时对象
对象在面向对象编程中随处可见,甚至可以毫不夸张的说是:“一切都是对象”。如何更好的创建和使用对象,是优化中要考虑的一个重要方面。笔者将对象按使用分为两大类:独享对象和共享对象。独享对象指由某个线程单独拥有并维护其生命周期的对象,一般是通过new 创建的对象,线程结束且无其它对这个对象的引用,这个对象将由垃圾收集机制自动GC。共享对象指由多个线程共享的对象,各线程保持多个指向同一个对象的引用,任何对这个对象的修改都会在其它引用上得到体现,共享对象一般通过Factory工厂的getInstace()方法创建,单例模式就是创建共享对象的标准实现。独享对象由于无其它指向同一对象的引用,不用担心其它引用对对象属性的修改,在多线程环境里,也就不需要对其可能修改属性的方法加以同步,减少了出错的隐患和复杂性,但由于需要为每个线程都创建对象,增加了对内存的需求和JVM GC的负担。共享对象则需要进行适当的同步(避免较大的同步块,同时防止死锁)。
还有几种特殊对象:不变对象和方法对象。不变对象指对象对外不含有修改对象属性的方法(如set方法),外部要修改属性只能通过new新的实例来实现。不变对象最大的好处就是无需担心属性被修改,避免了潜在的bug,并能无需任何额外工作(如同步)就很好的工作在多线程环境下。如jdk的String对象就是典型的不变对象。方法对象简单的说就是仅包含方法,不含有属性的对象。由于没有对象属性,方法中无需进行修改属性的操作,也就能采用static方法或单例模式,避免每次使用都要new对象,减少对象的使用。
那么该如何确定创建何种对象,这就要结合对象的使用方式和生命周期、对象大小、构建花销等方面来综合考虑。如果对象生命周期较长,会存在修改操作,不能容忍其它线程对其的修改,就应该采用独享对象,如常见的Bean类。而如果对象生命周期较长,且能为各个线程共享,就可以考虑共享对象。共享有2种常见情况,一种是系统全局对象,如配置属性等,各个线程应该引用同一对象,任何对这个对象的修改都会影响其它线程;另一种是由于对象创建开销较大,各线程对此对象是瞬时访问,且无需再次读取其属性,如常见的Date 对象,一般这种对象的使用是瞬时的,比如把它format成String,如果每次创建然后等待GC就会浪费大量内存和CPU时间,较好做法就是做成共享对象,各个线程先set再使用,注意对进行set并访问的方法要同步。不变对象一般使用在对象创建开销较小(属性较少,类层次较少),且需要能自由共享的情形。如一个对象里的常量对象,使用public static final AAA=new AAA(…) 创建。方法对象使用较广,如Util类、DAO类等,这些对象提供操作其它对象(一般是bean对象)的接口,能对系统在层次和功能上进行解耦合。
条例二:在循环处,多下功夫
循环作为程序编写的基本语法,可以说是随处可见。一些小的细节能带来性能上的提升,而对循环体的一些改写,能带来性能的大幅提升。
比如最简单的List遍历,会有这样的写法:for(int i=0;i
同样是对List的'操作,如果要在遍历同时进行增加和删除操作,代码如下:for(int i=0,j=();i=0;i--){ve(i);}。经过测试,如果采用ArrayList,两种写法在循环次数较少时没有太大的区别,循环次数为1000,均为1ms以内,次数为10000,前一种为60ms左右,后一种为1ms以内,,而次数上到100000,前一种为6000ms左右,后一种为15ms,随着循环次数的增多,后一种较前一种的效率优势明显提高。
这是由Collection库ArrayList的实现决定的,以下是jdk1.3的ArrayList源码:
从中我们可以看出,numMoved代表了需要进行arraycopy操作的数量,它是由remove的位置决定的,如果index=0,也就是删除第一个元素,则需要arraycopy后面的所有数据,而如果index=size-1,则只需将最后一个元素设为null即可。所以从后面向前循环remove是比较好的写法。
如果List中的确存在较多的add或remove操作,且容量较大(如存储几万个对象),则应该采用LinkedList作为实现。LinkedList内部采用双向链表作为数据结构,比ArrayList占用较多内存空间,且随机访问操作较慢(需要从头或尾循环到相应位置),但插入删除操作很快(仅需进行链表操作,无须大量移动或拷贝)。
对于List操作如果循环规模较小,其实对性能影响非常小(ms级),远远不是性能瓶颈所在。但心中有着优化的意识,并力求写出简洁高效的程序应该是我们每个程序员的追求。而且一旦在循环规模较大时,如果有了这些意识,也就能有效的消除性能隐患。
再举一个与优化无关但确实可能成为性能杀手(可以说是bug)的循环的例子。下面是源代码:
这个代码意图很清楚,就是将一个InputStream流读到一个byte数组中去。它使用read方法循环读取InputStream,该方法返回读取的字节数。正常情况下,该循环运行良好,当totalRead=m_totalBytes时,结束循环,byte数组被正常填充。但如果仔细看一下InputStream的read方法的说明,了解一下其返回值就会发现,返回值可能为-1,即已读到InputStream末尾再继续读时。如果发生读取异常,可能出现这个问题,而这个循环没有检查readBytes值是否为-1就往totalRead上加,这样再次进入循环体继续读取InputStream,又返回-1,继续循环。如此循环直到int溢出才会跳出循环。而这个循环也就成了实实在在的CPU杀手,可以占去大量的CPU时间(取决于操作系统)。其实解决很简单,对readBytes进行判断,如果为-1则跳出循环。
这个例子告诉我们:对循环一定要搞清循环的循环规模、每次循环体执行时间、循环结束条件包括异常情况等,只有这样才能写出高效且没有隐患的代码。
相關文章
-
J2EE系统优化之对象与循环简介
优化一般意义上说是提高已有系统的性能,减少如内存、数据库、网络带宽等资源的占用,是在系统开发告一段落的前提下进行。yjbys小编分享一篇J2EE系统优化之对象与循环给大家,希望大家认真阅读!条例一:尽量重用对象,避免创建 -
J2EE架构环境监控系统设计
下面是小编整理的从环境监控实际出发设计采用了基于J2EE开发平台、B/S模式的环境监控系统设计方案。并进行了系统的数据结构设计、三层结构的系统设计以及系统功能设计的文章。 一、系统主要模块本系统的功能为能 -
SUN认证考试知识点:OSCache提升J2EE系统运行性能
时间过得太快,让人猝不及防,又将迎来新的工作,新的挑战,为此需要好好地写一份计划了。你所接触过的计划都是什么样子的呢?下面是小编帮大家整理的年级工作计划10篇,仅供参考,大家一起来看看吧。年级工作计划 篇1一、 指导思 -
关于J2EE系统异常的处理准则
J2EE核心是一组技术规范与指南,其中所包含的各类组件、服务架构及技术层次,均有共同的标准及规格,让各种依循J2EE架构的不同平台之间,存在良好的兼容性。下面是小编整理的关于J2EE系统异常的处理准则,欢迎大家参考! J2E -
J2EE工程师知识点:JPA的优势
J2EE规范是这样定义J2EE组件的:客户端应用程序和applet是运行在客户端的组件;Java Servlet和Java Server Pages (JSP) 是运行在服务器端的Web组件;Enterprise Java Bean (EJB )组件是运行在服务器端的业务组件。下面Y -
Eclipse j2ee开发环境的搭建
J2EE规范是这样定义J2EE组件的:客户端应用程序和applet是运行在客户端的组件。以下是关于Eclipse j2ee开发环境的搭建,欢迎大家参考!在Linux系统大家族中,Android无疑是最耀眼的一个。Android的开发也是在Linux系统中进 -
win10系统下安装Java SE与环境变量
好的演讲稿可以引导听众,使听众能更好地理解演讲的内容。在当下社会,需要使用演讲稿的事情愈发增多,为了让您在写演讲稿时更加简单方便,以下是小编整理的高中生感恩老师演讲稿,欢迎大家借鉴与参考,希望对大家有所帮助。高中 -
妇产科主治医师知识点:循环系统的变化
1.心脏心脏向左、向上、向前移位,心浊界稍扩大。心脏容量从妊娠早期至妊娠末期约增加10%,心率每分钟增加10~15次。心尖部闻及柔和吹风样收缩期杂音。 2.心搏量心搏量自妊娠10周增加,妊娠32~34周达高峰。 3.血压 -
j2ee培训:如何构建RESTful Web Service
JavaEE的核心是EJB3.0, 其提供了更兼便捷的企业级的应用框架。下面yjbys小编为大家准备了关于如何构建RESTful Web Service的.文章,欢迎阅读。 1. 首先是实体类,注意其中的@XmlRootElement注解package s;import ;imp -
j2ee和JSP的关系
J2EE是Java 2 Enterprise Eidtion,它们是Sun公司建立在Java语言上的一种服务器端的编程技术,简单来说,它是用来动态生成网页的一种技术,现在的主要对手是微软主推的。 JSP和J2EE的关系简述JSP应该是属于J2EE的一部分,JS