广交好友~~ 想要讨论的可以留下msn~~~ 希望群友网友经常能提出问题,一起解决,共同提高

js优化2---集合贴

上一篇 / 下一篇  2010-12-23 17:57:14 / 个人分类:Java&C

随着网络的发展,网速和机器速度的提高,越来越多的网站用到了丰富客户端技术。而现在Ajax则是最为流行的一种方式。JavaScript是一种解释型 语言,所以能无法达到和C/Java之类的水平,限制了它能在客户端所做的事情,为了能改进他的性能,我想基于我以前给JavaScript做过的很多测 试来谈谈自己的经验,希望能帮助大家改进自己的JavaScript脚本性能。

语言层次方面
    循环
    循环是很常用的一个控制结构,大部分东西要依靠它来完成,在JavaScript中,我们可以使用for(;;),while(),for(in)三种循 环,事实上,这三种循环中for(in)的效率极差,因为他需要查询散列键,只要可以就应该尽量少用。for(;;)和while循环的性能应该说基本 (平时使用时)等价。

    而事实上,如何使用这两个循环,则有很大讲究。我在测试中有些很有意思的情况,见附录。最后得出的结论是:

    如果是循环变量递增或递减,不要单独对循环变量赋值,应该在它最后一次读取的时候使用嵌套的++或—操作符。

    如果要与数组的长度作比较,应该事先把数组的length属性放入一个局部变量中,减少查询次数。

    局部变量和全局变量
    局部变量的速度要比全局变量的访问速度更快,因为全局变量其实是全局对象的成员,而局部变量是放在函数的栈当中的。

    不使用Eval
    使用eval相当于在运行时再次调用解释引擎对内容进行运行,需要消耗大量时间。这时候使用JavaScript所支持的闭包可以实现函数模版(关于闭包的内容请参考函数式编程的有关内容)

    减少对象查找
    因为JavaScript的解释性,所以a.b.c.d.e,需要进行至少4次查询操作,先检查a再检查a中的b,再检查b中的c,如此往下。所以如果这 样的表达式重复出现,只要可能,应该尽量少出现这样的表达式,可以利用局部变量,把它放入一个临时的地方进行查询。

    这一点可以和循环结合起来,因为我们常常要根据字符串、数组的长度进行循环,而通常这个长度是不变的,比如每次查询a.length,就要额外进行一个操作,而预先把var len=a.length,则就少了一次查询。

    字符串连接
    如果是追加字符串,最好使用s+=anotherStr操作,而不是要使用s=s+anotherStr。

    如果要连接多个字符串,应该少使用+=,如

s+=a;s+=b;s+=c;
应该写成

s+=a + b + c;
    而如果是收集字符串,比如多次对同一个字符串进行+=操作的话,最好使用一个缓存。怎么用呢?使用JavaScript数组来收集,最后使用join方法连接起来,如下

var buf = new Array();for(var i = 0; i < 100; i++){ buf.push(i.toString());}var all = buf.join("");
    类型转换
    类型转换是大家常犯的错误,因为JavaScript是动态类型语言,你不能指定变量的类型。

    1. 把数字转换成字符串,应用"" + 1,虽然看起来比较丑一点,但事实上这个效率是最高的,性能上来说:

("" +) > String() > .toString() > new String()

这条其实和下面的“直接量”有点类似,尽量使用编译时就能使用的内部操作要比运行时使用的用户操作要快。

String()属于内部函数,所以速度很快,而.toString()要查询原型中的函数,所以速度逊色一些,new String()用于返回一个精确的副本。

    2. 浮点数转换成整型,这个更容易出错,很多人喜欢使用parseInt(),其实parseInt()是用于将字符串转换成数字,而不是浮点数和整型之间的转换,我们应该使用Math.floor()或者Math.round()。

另外,和第二节的对象查找中的问题不一样,Math是内部对象,所以Math.floor()其实并没有多少查询方法和调用的时间,速度是最快的。

    3. 对于自定义的对象,如果定义了toString()方法来进行类型转换的话,推荐显式调用toString(),因为内部的操作在尝试所有可能性之后,会尝试对象的toString()方法尝试能否转化为String,所以直接调用这个方法效率会更高

    使用直接量
    其实这个影响倒比较小,可以忽略。什么叫使用直接量,比如,JavaScript支持使用[param,param,param,...]来直接表达一个 数组,以往我们都使用new Array(param,param,...),使用前者是引擎直接解释的,后者要调用一个Array内部构造器,所以要略微快一点点。

    同样,var foo = {}的方式也比var foo = new Object();快,var reg = /../;要比var reg=new RegExp()快。

    字符串遍历操作
    对字符串进行循环操作,譬如替换、查找,应使用正则表达式,因为本身JavaScript的循环速度就比较慢,而正则表达式的操作是用C写成的语言的API,性能很好。

    高级对象
    自定义高级对象和Date、RegExp对象在构造时都会消耗大量时间。如果可以复用,应采用缓存的方式。

DOM相关
    插入HTML
    很多人喜欢在JavaScript中使用document.write来给页面生成内容。事实上这样的效率较低,如果需要直接插入HTML,可以找一个容 器元素,比如指定一个div或者span,并设置他们的innerHTML来将自己的HTML代码插入到页面中。

    对象查询
    使用[“”]查询要比.items()更快,这和前面的减少对象查找的思路是一样的,调用.items()增加了一次查询和函数的调用。

    创建DOM节点
    通常我们可能会使用字符串直接写HTML来创建节点,其实这样做无法保证代码的有效性字符串操作效率低,所以应该是用 document.createElement()方法,而如果文档中存在现成的样板节点,应该是用cloneNode()方法,因为使用 createElement()方法之后,你需要设置多次元素的属性,使用cloneNode()则可以减少属性的设置次数——同样如果需要创建很多元 素,应该先准备一个样板节点。

    定时器
    如果针对的是不断运行的代码,不应该使用setTimeout,而应该是用setInterval。setTimeout每次要重新设置一个定时器。

    其他
    脚本引擎
    据我测试Microsoft的JScript的效率较Mozilla的Spidermonkey要差很多,无论是执行速度还是内存管理上,因为JScript现在基本也不更新了。但SpiderMonkey不能使用ActiveXObject

    文件优化
    文件优化也是一个很有效的手段,删除所有的空格和注释,把代码放入一行内,可以加快下载的速度,注意,是下载的速度而不是解析的速度,如果是本地,注释和空格并不会影响解释和执行速度。

    总结
    本文总结了我在JavaScript编程中所找到的提高JavaScript运行性能的一些方法,其实这些经验都基于几条原则:

    直接拿手头现成的东西比较快,如局部变量比全局变量快,直接量比运行时构造对象快等等。

    尽可能少地减少执行次数,比如先缓存需要多次查询的。

    尽可能使用语言内置的功能,比如串链接。

     尽可能使用系统提供的API,因为这些API是编译好的二进制代码,执行效率很高

     同时,一些基本的算法上的优化,同样可以用在JavaScript中,比如运算结构的调整,这里就不再赘述了。但是由于JavaScript是解释型的,一般不会在运行时对字节码进行优化,所以这些优化仍然是很重要的。

    当然,其实这里的一些技巧同样使用在其他的一些解释型语言中,大家也可以进行参考。



    

    ava在九十年代中期出现以后,在赢得赞叹的同时,也引来了一些批评。赢得的赞叹主要是java的跨平台的操作性,即所谓的”write once,run anywhere”.但由于java的性能和运行效率同c相比,仍然有很大的差距,从而引来了很多的批评。
对于服务器端的应用程序,由于不大涉及到界面设计和程序的频繁重启,java的性能问题看似不大明显,从而一些java的技术,如jsp,se rvlet,ejb等在服务器端编程方面得到了很大的应用,但实际上,java的性能问题在服务器端依然存在。下面我将分四个方面来讨论java的性能和 执行效率以及提高j ava性能的一些方法。
一.关于性能的基本知识
1.性能的定义
在我们讨论怎样提高java的性能之前,我们需要明白“性能“的真正含义。我们一般定义如下五个方面作为评判性能的标准。
1) 运算的性能----哪一个算法的执行性能最好
2) 内存的分配----程序需要分配多少内存,运行时的效率和性能最高。
3) 启动的时间----程序启动需要多少时间。
4) 程序的可伸缩性-----程序在用户负载过重的情况下的表现。
5) 性能的认识------用户怎样才能认识到程序的性能。
对于不同的应用程序,对性能的要求也不同。例如,大部分的应用程序在启动时需要较长的时间,从而对启动时间的要求有所降低;服务器端的应用程序通 常都分配有较大的内存空间,所以对内存的要求也有所降低。但是,这并不是所这两方面的性能可以被忽略。其次,算法的性能对于那些把商务逻辑运用到事务性操 作的应用程序来讲非常重要。总的来讲,对应用程序的要求将决定对各个性能的优先级。
2.怎样才能提高java的性能
提高java的性能,一般考虑如下的四个主要方面:
(1) 程序设计的方法和模式
一个良好的设计能提高程序的性能,这一点不仅适用于java,也适用也任何的编程语言。因为它充分利用了各种资源,如内存,cpu,高速缓存,对象缓冲池及多线程,从而设计出高性能和可伸缩性强的系统。
当然,为了提高程序的性能而改变原来的设计是比较困难的,但是,程序性能的重要性常常要高于设计上带来的变化。因此,在编程开始之前就应该有一个好的设计模型和方法。
(2) java布署的环境。
java布署的环境就是指用来解释和执行java字节码的技术,一般有如下五种。即解释指令技术(interpreter technology),及时编译的技术(just in time compilier technology), 适应性优化技术(adaptive optimization technology), 动态优化,提前编译为机器码的技术(dynamic optimization,ahead of time technology)和编译为机器码的技术(translator technology).
这些技术一般都通过优化线程模型,调整堆和栈的大小来优化java的性能。在考虑提高java的性能时,首先要找到影响java性能的瓶颈 (b ottlenecks),在确认了设计的合理性后,应该调整java布署的环境,通过改变一些参数来提高java应用程序的性能。具体内容见第二节。
(3) java应用程序的实现
当讨论应用程序的性能问题时,大多数的程序员都会考虑程序的代码,这当然是对的,当更重要的是要找到影响程序性能的瓶颈代码。为了找到这些瓶颈代 码,我们一般会使用一些辅助的工具,如j probe,optimizit,vtune以及一些分析的工具如towerj performance等。这些辅助的工具能跟踪应用程序中执行每个函数或方法所消耗掉的时间,从而改善程序的性能。
(4) 硬件和操作系统
为了提高java应用程序的性能,而采用跟快的cpu和更多的内存,并认为这是提高程序性能的唯一方法,但事实并非如此。实践经验和事实证明,只有遭到了应用程序性能的瓶颈,从而采取适当得方法,如设计模式,布署的环境,操作系统的调整,才是最有效的。
3.程序中通常的性能瓶颈。
所有的应用程序都存在性能瓶颈,为了提高应用程序的性能,就要尽可能的减少程序的瓶颈。以下是在java程序中经常存在的性能瓶颈。


了解了这些瓶颈后,就可以有针对性的减少这些瓶颈,从而提高java应用程序的性能
4. 提高java程序性能的步骤
为了提高java程序的性能,需要遵循如下的六个步骤。
a) 明确对性能的具体要求
在实施一个项目之前,必须要明确该项目对于程序性能的具体要求,如:这个应用程序要支持5000个并发的用户,并且响应时间要在5秒钟之内。但同时也要明白对于性能的要求不应该同对程序的其他要求冲突。
b) 了解当前程序的性能
你应该了解你的应用程序的性能同项目所要求性能之间的差距。通常的指标是单位时间内的处理数和响应时间,有时还会比较cpu和内存的利用率。
c) 找到程序的性能瓶颈
为了发现程序中的性能瓶颈,通常会使用一些分析工具,如:towerj application performance analyzer或vtune来察看和分析程序堆栈中各个元素的消耗时间,从而正确的找到并改正引起性能降低的瓶颈代码,从而提高程序的性能。这些工具还 能发现诸如过多的异常处理,垃圾回收等潜在的问题。
d) 采取适当的措施来提高性能
找到了引起程序性能降低的瓶颈代码后,我们就可以用前面介绍过的提高性能的四个方面,即设计模式,java代码的实现,布署java的环境和操作系统来提高应用程序的性能。具体内容将在下面的内容中作详细说明。
e) 只进行某一方面的修改来提高性能
一次只改变可能引起性能降低的某一方面,然后观察程序的性能是否有所提高,而不应该一次改变多个方面,因为这样你将不知道到底哪个方面的改变提高了程序的性能,哪个方面没有,即不能知道程序瓶颈在哪。
f) 返回到步骤c,继续作类似的工作,一直达到要求的性能为止。

二. java布署的环境和编译技术
 开发java应用程序时,首先把java的源程序编译为与平台无关的字节码。这些字节码就可以被各种基于jvm的技术所执行。这些技术主要分为两个大类。即基于解释的技术和基于提前编译为本地码的技术。其示意图如下:


具体可分为如下的五类:  
a) 解释指令技术
其结构图和执行过程如下:


 java的编译器首先把java源文件编译为字节码。这些字节码对于java虚拟机(jvm)来讲就是机器的指令码。然后,java的解释器不断的循环取出字节码进行解释并执行。
 这样做的优点是可以实现java语言的跨平台,同时生成的字节码也比较紧凑。java的一些优点,如安全性,动态性都得保持;但缺点是省生成的字节码没有经过什么优化,同全部编译好的本地码相比,速度比较慢。
b) 及时编译技术(just in time)
  及时编译技术是为了解决指令解释技术效率比较低,速度比较慢的情况下提出的,其结构图如下所示。


其主要变化是在java程序执行之前,又jit编译器把java的字节码编译为机器码。从而在程序运行时直接执行机器码,而不用对字节码进行解释。同时对代码也进行了部分的优化。
这样做的优点是大大提高了java程序的性能。同时,由于编译的结果并不在程序运行间保存,因此也节约了存储空间了加载程序的时间;缺点是由于j it编译器对所有的代码都想优化,因此也浪费了很多的时间。
ibm和sun公司都提供了相关的jit产品。
c) 适应性优化技术(adaptive optimization technology)
同jit技术相比,适应性优化技术并不对所有的字节码进行优化。它会跟踪程序运行的成个过程,从而发现需要优化的代码,对代码进行动态的优化。对优化的代码,采取8 0/20的策略。从理论上讲,程序运行的时间越长,代码就越优化。其结构图如下:


其优点是适应性优化技术充分利用了程序执行时的信息,发行程序的性能瓶颈,从而提高程序的性能;其缺点是在进行优化时可能会选择不当,发而降低了程序的性能。
其主要产品又ibm,sun的hotspot.
d) 动态优化,提前编译为机器码的技术(dynamic optimization,ahead of time)
动态优化技术充分利用了java源码编译,字节码编译,动态编译和静态编译的技术。其输入时java的原码或字节码,而输出是经过高度优化的可执行代码和个来动态库的混合( window中是dll文件,unix中是共享库.a .so文件)。其结构如下:


其优点是能大大提高程序的性能;缺点是破坏了java的可移植性,也对java的安全带来了一定的隐患。

java性能的优化(下)


--------------------------------------------------------------------------------


黄伟峰




三.优化java程序设计和编码,提高java程序性能的一些方法。
通过使用一些前面介绍过的辅助性工具来找到程序中的瓶颈,然后就可以对瓶颈部分的代码进行优化。一般有两种方案:即优化代码或更改设计方法。我们 一般会选择后者,因为不去调用以下代码要比调用一些优化的代码更能提高程序的性能。而一个设计良好的程序能够精简代码,从而提高性能。
下面将提供一些在java程序的设计和编码中,为了能够提高java程序的性能,而经常采用的一些方法和技巧。
1.对象的生成和大小的调整。
java程序设计中一个普遍的问题就是没有好好的利用java语言本身提供的函数,从而常常会生成大量的对象(或实例)。由于系统不仅要花时间生成对象,以后可能还需花时间对这些对象进行垃圾回收和处理。因此,生成过多的对象将会给程序的性能带来很大的影响。
例1:关于string ,stringbuffer,+和append
java语言提供了对于string类型变量的操作。但如果使用不当,会给程序的性能带来影响。如下面的语句:
string name=new string(“huangweifeng”);
system.out.println(name+”is my name”);
看似已经很精简了,其实并非如此。为了生成二进制的代码,要进行如下的步骤和操作。
(1) 生成新的字符串 new string(str_1);
(2) 复制该字符串。
(3) 加载字符串常量”huangweifeng”(str_2);
(4) 调用字符串的构架器(constructor);
(5) 保存该字符串到数组中(从位置0开始)
(6) 从java.io.printstream类中得到静态的out变量
(7) 生成新的字符串缓冲变量new stringbuffer(str_buf_1);
(8) 复制该字符串缓冲变量
(9) 调用字符串缓冲的构架器(constructor);
(10) 保存该字符串缓冲到数组中(从位置1开始)
(11) 以str_1为参数,调用字符串缓冲(stringbuffer)类中的append方法。
(12) 加载字符串常量”is my name”(str_3);
(13) 以str_3为参数,调用字符串缓冲(stringbuffer)类中的append方法。
(14) 对于str_buf_1执行tostring命令。
(15) 调用out变量中的println方法,输出结果。
由此可以看出,这两行简单的代码,就生成了str_1,str_2,str_3,str_4和str_buf_1五个对象变量。这些生成的类的实 例一般都存放在堆中。堆要对所有类的超类,类的实例进行初始化,同时还要调用类极其每个超类的构架器。而这些操作都是非常消耗系统资源的。因此,对对象的 生成进行限制,是完全有必要的。
经修改,上面的代码可以用如下的代码来替换。
stringbuffer name=new stringbuffer(“huangweifeng”);
system.out.println(name.append(“is my name.”).tostring());
系统将进行如下的操作。
(1) 生成新的字符串缓冲变量new stringbuffer(str_buf_1);
(2) 复制该字符串缓冲变量
(3) 加载字符串常量”huangweifeng”(str_1);
(4) 调用字符串缓冲的构架器(constructor);
(5) 保存该字符串缓冲到数组中(从位置1开始)
(6) 从java.io.printstream类中得到静态的out变量
(7) 加载str_buf_1;
(8) 加载字符串常量”is my name”(str_2);
(9) 以str_2为参数,调用字符串缓冲(stringbuffer)实例中的append方法。
(10) 对于str_buf_1执行tostring命令。(str_3)
(11)调用out变量中的println方法,输出结果。
由此可以看出,经过改进后的代码只生成了四个对象变量:str_1,str_2,str_3和str_buf_1.你可能觉得少生成一个对象不会 对程序的性能有很大的提高。但下面的代码段2 的执行速度将是代码段1的2倍。因为代码段1生成了八个对象,而代码段2只生成了四个对象。
代码段1:
string name= new stringbuffer(“huangweifeng”);
name+=”is my”;
name+=”name”;
代码段2:
stringbuffer name=new stringbuffer(“huangweifeng”);
name.append(“is my”);
name.append(“name.”).tostring();
因此,充分的利用java提供的库函数来优化程序,对提高java程序的性能时非常重要的.其注意点主要有如下几方面;
(1) 尽可能的使用静态变量(static class variables)
如果类中的变量不会随他的实例而变化,就可以定义为静态变量,从而使他所有的实例都共享这个变量。
例:
public class foo
{
someobject so=new someobject();
}
就可以定义为:
public class foo
{
static someobject so=new someobject();
}
(2) 不要对已生成的对象作过多的改变。
对于一些类(如:string类)来讲,宁愿在重新生成一个新的对象实例,而不应该修改已经生成的对象实例。
例:
string name=”huang”;
name=”wei”;
name=”feng”;
上述代码生成了三个string类型的对象实例。而前两个马上就需要系统进行垃圾回收处理。如果要对字符串进行连接的操作,性能将得更差。因为系统将不得为此生成更多得临时变量。如上例1 所示。
(3) 生成对象时,要分配给它合理的空间和大小
java中的很多类都有它的默认的空间分配大小。对于stringbuffer类来讲,默认的分配空间大小是16个字符。如果在程序中使用stringbu ffer的空间大小不是16个字符,那么就必须进行正确的初始化。
(4) 避免生成不太使用或生命周期短的对象或变量。
对于这种情况,因该定义一个对象缓冲池。以为管理一个对象缓冲池的开销要比频繁的生成和回收对象的开销小的多。
(5) 只在对象作用范围内进行初始化。
java允许在代码的任何地方定义和初始化对象。这样,就可以只在对象作用的范围内进行初始化。从而节约系统的开销。
例:
someobject so=new someobject();
if(x==1) then
{
foo=so.getxx();
}
可以修改为:
if(x==1) then
{
someobject so=new someobject();
foo=so.getxx();
}
2.异常(exceptions)
java语言中提供了try/catch来发方便用户捕捉异常,进行异常的处理。但是如果使用不当,也会给java程序的性能带来影响。因此,要注意以下两点。
(1) 避免对应用程序的逻辑使用try/catch
如果可以用if,while等逻辑语句来处理,那么就尽可能的不用try/catch语句
(2) 重用异常
在必须要进行异常的处理时,要尽可能的重用已经存在的异常对象。以为在异常的处理中,生成一个异常对象要消耗掉大部分的时间。
3. 线程(threading)
一个高性能的应用程序中一般都会用到线程。因为线程能充分利用系统的资源。在其他线程因为等待硬盘或网络读写而 时,程序能继续处理和运行。但是对线程运用不当,也会影响程序的性能。
例2:正确使用vector类
vector主要用来保存各种类型的对象(包括相同类型和不同类型的对象)。但是在一些情况下使用会给程序带来性能上的影响。这主要是由v ector类的两个特点所决定的。第一,vector提供了线程的安全保护功能。即使vector类中的许多方法同步。但是如果你已经确认你的应用程序是 单线程,这些方法的同步就完全不必要了。第二,在v ector查找存储的各种对象时,常常要花很多的时间进行类型的匹配。而当这些对象都是同一类型时,这些匹配就完全不必要了。因此,有必要设计一个单线程 的,保存特定类型对象的类或集合来替代v ector类.用来替换的程序如下(stringvector.java):
public class stringvector
{
private string [] data;
private int count;
public stringvector() { this(10); // default size is 10 }
public stringvector(int initialsize)
{
data = new string[initialsize];
}
public void add(string str)
{
// ignore null strings
if(str == null) { return; }
ensurecapacity(count + 1);
data[count++] = str;
}

private void ensurecapacity(int mincapacity)
{
int ldcapacity = data.length;
if (mincapacity > oldcapacity)
{
string olddata[] = data;
int newcapacity = oldcapacity * 2;
data = new string[newcapacity];
system.arraycopy(olddata, 0, data, 0, count);
}
}
public void remove(string str)
{
if(str == null) { return // ignore null str }
for(int i = 0; i < count; i++)
{
// check for a match
if(data[i].equals(str))
{
system.arraycopy(data,i+1,data,i,count-1); // copy data
// allow previously valid array element be gcd
data[--count] = null;
return;
}
}
}
public final string getstringat(int index) {
if(index < 0) { return null; }
else if(index > count)
{
return null; // index is > # strings
}
else { return data[index]; // index is good }
}
/* * * * * * * * * * * * * * * *stringvector.java * * * * * * * * * * * * * * * * */
因此,代码:
vector strings=new vector();
strings.add(“one”);
strings.add(“two”);
string second=(string)strings.elementat(1);
可以用如下的代码替换:
stringvector strings=new stringvector();
strings.add(“one”);
strings.add(“two”);
string second=strings.getstringat(1);
这样就可以通过优化线程来提高java程序的性能。用于测试的程序如下(testcollection.java):
import java.util.vector;
public class testcollection
{
public static void main(string args [])
{
testcollection collect = new testcollection();
if(args.length == 0)
{
system.out.println(
"usage: java testcollection [ vector | stringvector ]");
system.exit(1);
}
if(args[0].equals("vector"))
{
vector store = new vector();
long start = system.currenttimemillis();
for(int i = 0; i < 1000000; i++)
{
store.addelement("string");
}
long finish = system.currenttimemillis();
system.out.println((finish-start));
start = system.currenttimemillis();
for(int i = 0; i < 1000000; i++)
{
string result = (string)store.elementat(i);
}
finish = system.currenttimemillis();
system.out.println((finish-start));
}
else if(args[0].equals("stringvector"))
{
stringvector store = new stringvector();
long start = system.currenttimemillis();
for(int i = 0; i < 1000000; i++) { store.add("string"); }
long finish = system.currenttimemillis();
system.out.println((finish-start));
start = system.currenttimemillis();
for(int i = 0; i < 1000000; i++) {
string result = store.getstringat(i);
}
finish = system.currenttimemillis();
system.out.println((finish-start));
}
}
}
/* * * * * * * * * * * * * * * *testcollection.java * * * * * * * * * * * * * * * * */
测试的结果如下(假设标准的时间为1,越小性能越好):


关于线程的操作,要注意如下几个方面。
(1) 防止过多的同步
如上所示,不必要的同步常常会造成程序性能的下降。因此,如果程序是单线程,则一定不要使用同步。
(2) 同步方法而不要同步整个代码段
   对某个方法或函数进行同步比对整个代码段进行同步的性能要好。
(3) 对每个对象使用多”锁”的机制来增大并发。
一般每个对象都只有一个”锁”,这就表明如果两个线程执行一个对象的两个不同的同步方法时,会发生”死锁”。即使这两个方法并不共享任何资源。为了避免这个问题,可以对一个对象实行”多锁”的机制。如下所示:
class foo
{
private static int var1;
private static object lock1=new object();
private static int var2;
private static object lock2=new object();
public static void increment1()
{
synchronized(lock1)
{
var1++;
}
}
public static void increment2()
{
synchronized(lock2)
{
var2++;
}
}
}
4.输入和输出(i/o)
输入和输出包括很多方面,但涉及最多的是对硬盘,网络或数据库的读写操作。对于读写操作,又分为有缓存和没有缓存的;对于数据库的操作,又可以有多种类型的j dbc驱动器可以选择。但无论怎样,都会给程序的性能带来影响。因此,需要注意如下几点:
(1) 使用输入输出缓冲
   尽可能的多使用缓存。但如果要经常对缓存进行刷新(flush),则建议不要使用缓存。
(2) 输出流(output stream)和unicode字符串
   当时用output stream和unicode字符串时,write类的开销比较大。因为它要实现unicode到字节(byte)的转换.因此,如果可能的话,在使用write类之前就实现转换或用o utputstream类代替writer类来使用。
(3) 当需序列化时使用transient
   当序列化一个类或对象时,对于那些原子类型(atomic)或可以重建的原素要表识为transient类型。这样就不用每一次都进行序列化。如果这些序列化的对象要在网络上传输,这一小小的改变对性能会有很大的提高。  
(4) 使用高速缓存(cache)
   对于那些经常要使用而又不大变化的对象或数据,可以把它存储在高速缓存中。这样就可以提高访问的速度。这一点对于从数据库中返回的结果集尤其重要。
(5) 使用速度快的jdbc驱动器(driver)
   java对访问数据库提供了四种方法。这其中有两种是jdbc驱动器。一种是用java外包的本地驱动器;另一种是完全的java驱动器。具体要使用哪一种得根据j ava布署的环境和应用程序本身来定。
5.一些其他的经验和技巧
(1) 使用局部变量
(2) 避免在同一个类中动过调用函数或方法(get或set)来设置或调用变量。
(3) 避免在循环中生成同一个变量或调用同一个函数(参数变量也一样)
(4) 尽可能的使用static,final,private等关键字
(5) 当复制大量数据时,使用system.arraycopy()命令。










 


TAG:

 

评分:0

我来说两句

Open Toolbar