选择显示字体大小

“快”在细节 j2ee程序的性能优化技巧


  应用j2ee平台开发的系统的性能是系统使用者和开发者都关注的问题,本文从服务器端编程时应注意的几个方面讨论代码对性能的影响,并总结一些解决的建议。

  关键词:性能,javaj2eeejbservlet,jdbc

  一、概要

  java 2 platform, enterprise edition (j2ee)是当前很多商业应用系统使用的开发平台,该技术提供了一个基于组件的方法来设计、开发、装配和部署企业级应用程序。j2ee平台提供了一个多层结构的分布式的应用程序模型,可以更快地开发和发布的新的应用解决方案。
j2ee是一种技术规范,定义了整个标准的应用开发体系结构和一个部署环境,应用开发者开发时只要专注于具体商业逻辑和商业业务规则的实现上,而其他的诸如事务、持久化、安全等系统开发问题可以由应用程序容器或者服务器处理,开发完成后,就可以方便地部署到实现规范的应用服务器中。

  作为网络上的商业应用系统,同时访问的人数是很多的,在大量访问的情况下,过多的资源请求和有限的服务器资源(内存、cpu时间、网络带宽等)之间就会出现矛盾,应用系统的性能就显得很重要了,有时正确的代码并不能保证项目的成功,性能往往是最后决定一个项目是否成功关键。

  本文主要从性能的角度出发,讨论j2ee服务器端的代码性能优化和提升。

  二、常见的java 编程

  j2ee语言基础是java,常用的java代码问题对应用系统的性能影响,下面讨论了一些应该注意方面。

  ·使用stringbuffer代替string

  当处理字符串的相加时,常见的写法是:..

string str1 = "hello";
string str2 = "welcome to world";
string str3 = str1 + ", " + str2 +"!";
system.out.println(str3);

  很多人都知道,这样的代码效率是很低的,因为string是用来存储字符串常量的,如果要执行“+”的操作,系统会生成一些临时的对象,并对这些对象进行管理,造成不必要的开销。

  如果字符串有连接的操作,替代的做法是用stringbuffer类的append方法,它的缺省构造函数和append的实现是:

public stringbuffer() { // 构造函数
this(16); // 缺省容量16}

public synchronized stringbuffer append(string str) {
 if (str == null) {
  str = string.valueof(str);
 }

 int len =str.length();
 int newcount = count + len;
 if(newcount > value.length)

 expandcapacity(newcount);

 // 扩充容量
 str.getchars(0, len, value, count);
 count = newcount;
 return this;
}

  当字符串的大小超过缺省16时,代码实现了容量的扩充,为了避免对象的重新扩展其容量,更好的写法为:

stringbuffer buffer = new stringbuffer(30);
// 分配指定的大小。
buffer.append("hello");
buffer.append(",");
buffer.append("welcometo world!");
string str = buffer.tostring();

  ·生成对象时,分配合理的空间和大小

  java中的很多类都有它的默认的空间分配大小,对于一些有大小的对象的初始化,应该预计对象的大小,然后使用进行初始化,上面的例子也说明了这个问题,stringbuffer创建时,我们指定了它的大小。

  另外的一个例子是vector,当声明vector vect=new vector()时,系统调用:

public vector() {// 缺省构造函数
 this(10); // 容量是 10;
}

  缺省分配10个对象大小容量。当执行add方法时,可以看到具体实现为:..

public synchronized boolean add(object o) {
 modcount++;
 ensurecapacityhelper(elementcount+1);
 elementdata[elementcount++] =o;

 return true;
}

private void ensurecapacityhelper(int mincapacity) {
 int oldcapacity = elementdata.length;
 if (mincapacity > oldcapacity) {
  object olddata[] = elementdata;
  int newcapacity = (capacityincrement > 0) ? (oldcapacity + capacityincrement) :
(oldcapacity * 2);
  if (newcapacity < mincapacity) {
   newcapacity = mincapacity;
  }
  elementdata = new object[newcapacity];
  system.arraycopy(olddata, 0, elementdata, 0, elementcount);
 }
}

  我们可以看到,当vector大小超过原来的大小时,一些代码的目的就是为了做容量的扩充,在预先知道该vector大小的话,可以指定其大小,避免容量扩充的开销,如知道vector大小为100时,初始化是就可以象这样。

vector vect =.. new vector(100);

  ·优化循环体

  循环是比较重复运行的地方,如果循环次数很大,循环体内不好的代码对效率的影响就会被放大而变的突出。考虑下面的代码片:..

vector vect = new vector(1000);
...
for( inti=0; i<vect.size(); i++){
 ...
}

  for循环部分改写成:

int size = vect.size();
for( int i=0; i>size; i++){
 ...
}

  如果size=1000,就可以减少1000次size()的系统调用开销,避免了循环体重复调用。

  再看如下的代码片:..

for (int i = 0;i <100000;i++)
if (i&#37;10 == 9) {
 ... // 每十次执行一次
}

  改写成也可以提高效率:..

for(inti =0,j =10; i<100000; i++,j--){
 if(j == 0){
  ... // 每十次执行一次
  j = 10;
 }
}

  所以,当有较大的循环时,应该检查循环内是否有效率不高的地方,寻找更优的方案加以改进。

  ·对象的创建

  尽量少用new来初始化一个类的实例,当一个对象是用new进行初始化时,其构造函数链的所有构造函数都被调用到,所以new操作符是很消耗系统资源的,new一个对象耗时往往是局部变量赋值耗时的上千倍。同时,当生成对象后,系统还要花时间进行垃圾回收和处理。

  当new创建对象不可避免时,注意避免多次的使用new初始化一个对象。

  尽量在使用时再创建该对象。如:

newobject object = new newobject();
int value;
if(i>0 )
{
 value =object.getvalue();
}

  可以修改为:

int value;
if(i>0 )
{
 newobject object = new newobject();
 value =object.getvalue();
}

  另外,应该尽量重复使用一个对象,而不是声明新的同类对象。一个重用对象的方法是改变对象的值,如可以通过setvalue之类的方法改变对象的变量达到重用的目的。

  ·变量的注意事项

  尽量使用局部变量,调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(stack) 中,速度较快。其他变量,如静态变量、实例变量等,都在堆(heap)中创建,速度较慢。

  尽量使用静态变量,即加修饰符static,如果类中的变量不会随他的实例而变化,就可以定义为静态变量,从而使他所有的实例都共享这个变量。

  ·方法(method)调用

  在java中,一切都是对象,如果有方法(method)调用,处理器先要检查该方法是属于哪个对象,该对象是否有效,对象属于什么类型,然后选择合适的方法并调用。

  可以减少方法的调用,同样一个方法:

public void callmethod(int i ){
 if( i ==0 ){
  return;
 }
 ... // 其他处理
}

  如果直接调用,

int i = 0;
...
callmethod(i);

  就不如写成:

int i = 0;
...

if( i ==0 ){
 callmethod(i);
}

  不影响可读性等情况下,可以把几个小的方法合成一个大的方法。

  另外,在方法前加上final,private关键字有利于编译器的优化。

  ·慎用异常处理

  异常是java的一种错误处理机制,对程序来说是非常有用的,但是异常对性能不利。抛出异常首先要创建一个新的对象,并进行相关的处理,造成系统的开销,所以异常应该用在错误处理的情况,不应该用来控制程序流程,流程尽量用while,if等处理。

  在不是很影响代码健壮性的前提下,可以把几个try/catch块合成一个。

  ·同步

  同步主要出现在多线程的情况,为多线程同时运行时提供对象数据安全的机制,多线程是比较复杂话题,应用多线程也是为了获得性能的提升,应该尽可能减少同步。

  另外,如果需要同步的地方,可以减少同步的代码段,如只同步某个方法或函数,而不是整个代码。

  ·使用java系统api

  java的api一般都做了性能的考虑,如果完成相同的功能,优先使用api而不是自己写的代码,如数组复制通常的代码如下:

int size = 1000;
string[] strarray1 = new string[size];
string[] strarray2 = new string[size];
for(inti=0;i<size;i++){ // 赋值
 strarray1[i] = (new string("array: " + i));
}

for(inti=0;i<size;i++){ // 复制
 strarray2[i]=(new string((string)a[i]));
}

  如果使用java提供的api,就可以提高性能:

int size = 1000;
string[] strarray1 = new string[size];
string[] strarray2 = new string[size];
for(inti=0;i<size;i++){ // 赋值
strarray1[i] = (new string("array: " + i));
}

system.arraycopy(strarray1,0,strarray2,0,size); // 复制

  同样的一个规则是,当有大量数据的复制时,应该使用system.arraycopy()。


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons