第一篇:计算机系统性能优化总结
计算机系统性能优化总结
现今,计算机技术在社会各行各业都得到了广泛的应用。计算机给我们的学习、生活和工作都带来了极大的便利。但随着我们对计算机整体性能要求的提高,计算机系统性能的优化就显得尤为重要。
一、计算机系统运行不佳的原因分析
计算机系统运行性能不佳的原因有很多。如,系统平台结构不好、系统配置不好或参数设置不对;应用系统数据结构设计不合理,加大了系统的输入和输出需求;应用系统算法或逻辑处理有问题,使计算机系统达不到最佳的运行状态。
二、计算机系统性能优化措施
1.合理地配置各种软件,使计算机系统发挥最好的功能。计算机系统由硬件系统和软件系统组成,二者之间相互依赖,这就要求我们在使用计算机软件的过程中,使用一些速度较快、版本较高和功能较完善的软件,并仔细阅读各种软件的使用说明,避免在应用过程中发生冲突。作为编程人员,在编写应用程序的过程中,要充分考虑应用系统数据结构设计的合理性,以便使计算机系统达到最佳的运行状态。
2.调整输入和输出系统。在计算机系统的应用过程中,我们进行的大多数操作就是输入和输出。因此,输入和输出操作是影响计算机性能的一个重要因素。随着科技的日益发
展,磁盘的平均寻址时间日益缩短,但与中央处理器的运算相比,仍然缓慢很多。在观察一些系统运行时,经常出现中央处理器处在空闲状态而应用程序却迟迟不能完成的情况。究其原因,就是因为磁盘的输入和输出的速度太慢,数据没有读(写)入内存中。因此,在实际的应用过程中,我们可以考虑把数据文件存放在不同的磁盘上,让多个磁盘并行工作,从而解决输入和输出的瓶颈问题。如果输入和输出总数明显不合理,就要考虑查找引起输入和输出数量增大的原因,从而优化应用程序,减少输入和输出的次数,提高系统的性能。
3.安排相同性质的处理过程同时运行,以确保中央处理器和输入和输出的绝对通畅。一台计算机能够同时运行多个应用程序,从使用系统资源的角度来看,这些应用程序可以分为面向输入和输出与面向运算2种类型。
系统中如果有2个或多个面向输入和输出的应用在同时运行,就会造成中央处理器闲置而大量磁盘输入和输出拥塞和等待的情况,使得各个应用程序的性能变差。系统中如果有2个或多个面向运算的应用程序同时运行时,就会造成磁盘空转的情况。因此,要尽量避免让多个面向输入和输出或多个面向运算的应用程序同时运行。最好的安排就是让面向输入和输出与面向运算的应用程序合理搭配,使每个应用都能获得足够的系统服务而又互不影响。
4.合理地使用中央处理器。一般来说,在一个计算机系统中,中央处理器的速度要远远高于输入和输出的速度,因而输入和输出速度往往是影响系统性能的主要因素。但必须指出的是,这种规则只适用于普通的情况。如果不知道中央处理器能力也有一定限制,盲目地、不合理地使用中央处理器,中央处理器也会成为影响系统性能的主要因素。
通过对计算机系统的性能进行优化,排除了系统中的各种不合理因素,缩短了系统的响应时间,使计算机系统能更好地发挥作用,从而为我们提供更好的服务。
第二篇:网站前端性能优化总结
一、服务器侧优化
1.添加 Expires 或 Cache-Control 信息头
某些经常使用到、并且不会经常做改动的图片(banner、logo等等)、静态文件(登录首页、说明文档等)可以设置较长的有效期(expiration date),这些HTTP头向客户端表明了文档的有效性和持久性。如果有缓存,文档就可以从缓存(除已经过期)而不是从服务器读取。接着,客户端考察缓存中的副本,看看是否过期或者失效,以决定是否必须从服务器获得更新。
各个容器都有针对的方案,,以 Apache 为例:
ExpiresActive On ExpiresByType image/gif “access plus 1 weeks”
表示gif文件缓存一周,配置可以根据具体的业务进行调整,具体配置可以参考:http://lamp.linux.gov.cn/Apache/ApacheMenu/mod/mod_expires.html
2.压缩内容
对于绝大多数站点,这都是必要的一步,能有效减轻网络流量压力。
表示zlib在压缩时可以最大程度的使用内存,压缩html、文本、xml和php这几种类型的文件,指定扩展名为html、htm、xml、php、css和js的文件启用压缩。
具体配置可以参考:http://lamp.linux.gov.cn/Apache/ApacheMenu/mod/mod_deflate.html
3.设置 Etags
在使用etags之前,有必要复习一下 RFC2068 中规定的返回值 200 和 304 的含义:
200--OK 304--Not Modified
客户端在请求一份文件的时候,服务端会检查客户端是否存在该文件,如果客户端不存在该文件,则下载该文件并返回200;如果客户端存在该文件并且该文件在规定期限内没有被修改(Inode,MTime和Size),则服务端只返回一个304,并不返回资源内容,客户端将会使用之前的缓存文件。而etags就是判断该文件是否被修改的记号,与服务器端的资源一一关联,所以etags对于CGI类型的页面缓存尤其有用。
下图是优化前的首页:(注意,此时没有压缩首页图片,即使使用了缓存,仍需要5s左右的时间)
化前的某页面
需要注意的是,使用etags会增加服务器端的负载,在实际应用中需要自行平衡。
二、Cookie优化
1.减小Cookie体积
HTTP coockie可以用于权限验证和个性化身份等多种用途。coockie内的有关信息是通过HTTP文件头来在web服务器和浏览器之间进行交流的。因此保持coockie尽可能的小以减少用户的响应时间十分重要。
使cookie体积尽量小;
在合适的子域名上设置bookie,以免影响其他子域名下的响应;
设置合理的过期时间,去掉不必要的cookie。
下面对比一下各个网站的cookie:
图中可以看出,6K的cookie显然是不必要的。
2.对于页面内容使用无coockie域名
当浏览器在请求中同时请求一张静态的图片和发送coockie时,服务器对于这些coockie不会做任何地使用。因此它们只是因为某些负面因素而创建的网络传输。所以你应该确定对于静态内容的请求是无coockie的请求。创建一个子域名并用他来存放所有静态内容。
例如,域名是
3.切分组件到多个域
主要的目的是提高页面组件并行下载能力,但注意,也不要同时使用过多的域名,否则就会出现第一条DNS lookup过多的问题,一般情况下两个域名就可以了。
4.杜绝 http 404 错误
对页面链接的充分测试加上对 Web 服务器 error 日志的不断跟踪可以有效减少 404 错误,并提升用户体验。
后记:
这次总结给我带来的启发并不在于提升系统性能性能本身,提升性能只是一个很表面上的东西,网上的方法有很多,测试的方法也有很多,照着都做一遍,性能确实会有所提升,但是这种知其然而不知其所以然的性能提升是没有意义的,这便是本文的目的所在。
第三篇:SQL语句性能优化
我也做了很长时间医疗软件,也写过不少sql优化,没有详细记录下来,个人感觉下面转载的更符合医院医疗软件实际业务,很认可大部分所写的原则,固转载过来,以作借鉴。软件的根本还是在于更细更精,在于从客户的实际使用考虑问题。
性能优化原则1:永远避免困境
利用缓存把字典数据取到中间服务器或是客户端替代直接sql查询,如,门诊医生站把字典下载到客户端,减少执行次数。
一次性取数据到客户端,然后再逐条处理,而不是分次取数据,处理好一条数据再取下一条再处理。例:门诊收费取hjcfmxk例子,原来是一张处方条明细都查询一次,查询后再处理,现改为一次把所有明细都取过来,然后一条条处理
尽量减少光标,看能不能用临时表
性能优化原则2:kiss原则
对于where 条件中的左边可以利用索引的字段Keep it simple stupid,左边尽量避免用函数(substring,isnull,upper,lower),参加计算+,-*/
例子1:select * from ZY_BRFYMXK where substring(zxrq,1,8)='20081212‘
select * from ZY_BRFYMXK where zxrq between '2008121200' and '2008121224' 例子2:
select * from zy_detail_charge where SUBSTRING(patient_id,1,10)=
substring('000005090600',1,10)这句耗时30秒以上
select * from zy_detail_charge where patient_id like substring('000005090600',1,10)+'%' 这句耗时2秒以内
性能优化原则3:尽可能利用到索引
例:select * from ZY_BRFYMXK a(nolock),VW_LSYZK b(nolock)where a.syxh=3 and a.yzxh=b.xh and a.fylb=0
select * from ZY_BRFYMXK a(nolock),VW_LSYZK b(nolock)where a.syxh=3 and a.yzxh=b.xh and a.fylb=0 and b.syxh=3
性能优化原则4:or,避而远之
对于索引字段尽力避免用or,普通字段可以用or,解决要么分解成多个sql,要么用业务规则避免,例:declare @rq1 ut_rq16,@syxh ut_syxh
select @rq1='20081201'
select @syxh=157
性能优化原则5:避免大批量数据取到前台
例: select * from ZY_BRSYK cyrq between ‘20080901’ and ‘20081201‘,对于大医院每天100多人,90天是9000条数据
性能优化原则6:事务,尽可能的短吧
所有计算、对临时表的更新都应但放在事务外,事务中最好只有更新和插入正式表操作.因为事务中产生的锁只有在commit tran是才会释放。
性能优化原则7:热表,留在最后吧
热表是频繁调用的表。如:sf_mzcfk,zy_brfymxk,bq_fyqqk.对于热表尽量放在事务最后:这样锁的时间短。大家都坚持这样,死锁的可能性就小。如果都是热表各个存储过程更新表的顺序应当一样这样可以避免死锁
性能优化原则8:创建临时表一定要避免在事务中作
如create #tempXX(…)
Select * into #tempXX from …
因为创建临时表会锁tempdb的系统表
例:生成#temp1放在事务内外,用sp_lock2 ‘’观察结果
if object_id('tempdb..#temp1','U')is not null
drop table #temp1
begin tran
select * into #temp1 from ZY_BRSYK where ryrq>'20080901‘
select * from #temp1
waitfor delay '00:00:10'
commit
性能优化原则9:大的报表查询避免与正常业务碰撞
如果没有查询服务器,那要在存储过程中限制不能操作加上如:
declare @rq1 ut_rq16,@rq2 ut_rq16,@now ut_rq16
select @rq1=convert(varchar(8),getdate(),112)+'08:00:00'
select @rq1=convert(varchar(8),getdate(),112)+'11:30:00'
select @now=convert(char(8),getdate(),112)+convert(char(8),getdate(),8)
if @now>@rq1 and @now<@rq2
begin
select '上午繁忙时间段不能作此查询'
return
end
性能优化原则10:存储过程避免大的if…else…
这个常出项在业务相同表不同的存储过程中,因为这样常到if …else …原来医技接口中很多这种存储过程,当时把门诊住院业务放在一个存储过程中。这样最大的问题是sql server会根据sql语句来compile存储,这个过程会生成优化计划,决定用那个索引。如果存储过程用到门诊表compile一下,到用到住院表是发现不对,又会compile一下,这样不停compile.compile很号时间要1-2秒,而且一个存储过成在compile是,所有调用这个存储过程的进程都要在排队等候,因为他会独占锁这个存储过程
例:usp_yjjk_getwzxxm_old.sql,后改为:
usp_yjjk_getwzxxm.sql, usp_yjjk_getwzxxm_mz.sql,usp_yjjk_getwzxxm_zy.sql
性能优化原则11:进攻是最好的防守
在普通编程语句对于数据校验总是用防守办法先判断,后再作相应处理。而在sql中先处理再判断性能会好很多。
--更新药品库存。
If exists(select 1 from YK_YKZKC WHERE idm=100 and kcsl>50)
begin
update YK_YKZKC set kcsl=kcsl-50 where idm=100
End
Else begin
rollback tran
Select ‘F库存不够’
return
end
--改为
update YK_YKZKC set kcsl=kcsl-50 where idm=100 and kcsl>50
If @@rowcount<=0
Begin
Rollbakc tran
Select ‘F库存不够’
end
--取未执行的医技项目,日表没有数据就到年表中查找
if exists(select a.* from SF_MZCFK a(nolock),SF_CFMXK b(nolock)
begin
select a.* into #temp1 from SF_MZCFK a(nolock),SF_CFMXK b(nolock)
end
else begin
select a.* into #temp1 from SF_NMZCFK a(nolock),SF_NCFMXK b(nolock)
end
--改为
Insert into #temp1 select a.*
from SF_MZCFK a(nolock),SF_CFMXK b(nolock)
If @@rowcount=0
Begin
Insert into #temp1 select a.*
from SF_NMZCFK a(nolock),SF_NCFMXK b(nolock)
end
性能优化原则12:trig最后的手段
Trig(触发器)的处理的处理机制是满足条件时就会在源语句后面加上trig中的代码进行执行。
它有两个致命的弊端:(1)不清楚有trig的人会对于执行结果感到迷惑。如常有在插入一张表如果主键是indentity的值常取用select @@identity。但如是有trig,tring中有表插入操作,这时的@@identity可能就不是想要的值。(2)trig会束缚选择。如:有一套单据主表和明细表,当明细表的金额更新时,要同步主表的金额,当程序是一条条更新明细时用trig的作法是每当更新一条明细记录时都算一处所有明细表的总金额,再去更新主表的金额。这样有多少条明细就要算多少次,好的作法是不要trig,直接在sql语句中明细更新完明后,一次性算出总金额每条单据的总金额,再更新主表的金额。
对于trig如果有其他手段就一定要避免用trig.性能优化原则13:用户说好才是真的好
1)有时sql语句性能难以优化,但用户对于系统响应速度还是不满意。这时可以从业务分析处理。
如:我们退费模块录入发票号原来是用fph like ‘XXX%’。用户报怨慢,后来改为先用fph=‘XXX’来查,如查不到再fph like ‘XXX%’。这样在绝大部情况下速度都非常快,同时也满足小部分情况下模糊查询的需求。
如:我们的程序要查日表和年表。如果通过日表union表视图去查会非常慢,性能也难以优化。程序改为普通情况下不查年表,用户勾上年表标志时才查年表。
(2)查询统计很多数据时间比较长,就以查询完一部分数据后可以显示这部分数据或是用提示,这样用户清楚系统在作事情也知道大概进度。这样情绪上会好很多。
(3)查询模块常有一进入时也默认一个查询,如果性能好,查询又合用户心意,这种设计非常好,如果性能不好,那就不是好的设计。用户对于进入都困难的模块是没有好感的。
(4)有户的耐心与查询出的记录成正比。用户痛恨等待很久却没有查询出记录。
对于非常慢的查询,如果有些子查询非常快可以先作这样查询以避免查询很久却没有数据出来的情况。如:按病历号查在院病人所有费有明细,可以先查一下这个病历是不是有对应病人。
实战技巧1:用exists、in代替distinct
Distinct实际上是先收集再删除这样两步都耗资源。
Exists,in会隐式过滤掉重复的记录
例查自2009年以来有金额大于100的药品的病人
select distinct a.blh,a.hzxm from ZY_BRXXK a(nolock),ZY_BRSYK b(nolock),ZY_BRFYMXK c(nolock)where a.patid=b.patid and b.syxh=c.syxh and c.zxrq>'2009' and c.zje>100--改为
select a.blh,a.hzxm from ZY_BRXXK a where exists(select 1 from ZY_BRSYK
b(nolock),ZY_BRFYMXK c(nolock)where a.patid=b.patid and b.syxh=c.syxh and
c.zxrq>'2009'and c.zje>100)
实战技巧2:缩短union
select …from A,B,C,D,E1
where(E1的条件)
and(其他表联接条件)
union
select …from A,B,C,D,E2
where(E2的条件)
and(其他表接接条件)
改为
select …from A,B,C,D,(select...from E1where(E1条件)
union
select …from E2where(E2条件))E where(其他条件)
当涉及ABCD表部分耗资源而E1,E2不耗资源时是这样,如果反过来则改后的性能不一定好。查2009年4月后入院的在院病人在2905病区发生的所有费用明细
select a.hzxm,b.cyrq,d.ypmc,d.ypgg,c.ypsl/c.dwxs ypsl, c.ypdw
select a.hzxm,b.cyrq,d.ypmc,d.ypgg,c.ypsl/c.dwxs ypsl, c.ypdw
from ZY_BRXXK a(nolock),ZY_BRSYK b(nolock),ZY_BRFYMXK c(nolock),YK_YPCDMLK d where a.patid=b.patid and b.ryrq>'200904' and b.brzt not in(3,8,9)and b.syxh=c.syxh and c.bqdm='2905' and c.idm=d.idm
union all
select a.hzxm,b.cyrq,d.name,d.xmgg,c.ypsl/c.dwxs ypsl, c.ypdw
from ZY_BRXXK a(nolock),ZY_BRSYK b(nolock),ZY_BRFYMXK c(nolock),YY_SFXXMK d where a.patid=b.patid and b.ryrq>'200904' and b.brzt not in(3,8,9)and b.syxh=c.syxh and c.bqdm='2905' and c.ypdm=d.id and c.idm=0
--改为
select a.hzxm,b.cyrq,d.ypmc,d.ypgg,c.ypsl/c.dwxs ypsl, c.ypdw
from ZY_BRXXK a(nolock),ZY_BRSYK b(nolock),ZY_BRFYMXK c(nolock),(select ypmc,ypgg,ypdm,idm idm from YK_YPCDMLK union select name,xmgg,id,0 from YY_SFXXMK)d
where a.patid=b.patid and b.ryrq>'200904' and b.brzt not in(3,8,9)and b.syxh=c.syxh and c.bqdm='2905' and c.idm=d.idm and c.ypdm=d.ypdm
实战技巧3:合并sql
把表和where条件类似的两个或是多个sql合并为一个sql.--查2009年以后的普通、急诊、专家挂号人数
declare @ptghs int,@jzghs int,@zjghs int
select @ptghs=0,@jzghs=0,@zjghs=0
select @ptghs=count(*)from GH_GHZDK where ghrq>'2009' and ghlb=0
select @jzghs=count(*)from GH_GHZDK where ghrq>'2009' and ghlb=1
select @zjghs=count(*)from GH_GHZDK where ghrq>'2009' and ghlb=2
select @ptghs,@jzghs,@zjghs
--改为
select @ptghs=0,@jzghs=0,@zjghs=0
select @ptghs=sum(case when ghlb=0 then 1 else 0 end),@jzghs=sum(case when ghlb=1 then 1 else 0 end), @zjghs=sum(case when ghlb=2 then 1 else 0 end)
from GH_GHZDK where ghrq>'2009'
select @ptghs,@jzghs,@zjghs
实战技巧4:去掉游标
把游标当作编程语言的for,do---while的方式,很多情况下都可以去掉,如果光标中间sql语句只有一条一般都是可以去掉光标改为一句sql。
--查当天出院出院日期在2009年4月1到9日间病人的zfdj,zfje置为0
declare @syxh ut_syxh
declare cur1 cursor for select syxh from ZY_BRSYK where cyrq>='20090401' and cyrq<'20090410'
open cur1
fetch cur1 into @syxh
while @@fetch_status=0
begin
fetch cur1 into @syxh
end
close cur1
deallocate cur1
--改为
update ZY_BRFYMXK set zfdj=0,zfje=0
from ZY_BRFYMXK a,ZY_BRSYK b
where a.syxh=b.syxh and b.cyrq>='20090401' and b.cyrq<'20090410'
实战技巧5:取代count
利用内部函数代替
declare @count int
select * into #tmep1 from ZY_BRFYMXK WHERE zxrq>'200901'
select @count=@@rowcount—可以得到count值
select @count
select @count=count(*)from #tmep1—可以被取代
select @count
利用exists而不count判断有没有记录
declare @count int
Select @count=count(1)from ZY_BRFYMXK WHERE zxrq>'2009‘
If @count>0 … else ….--改为
If exists(Select 1 from ZY_BRFYMXK WHERE zxrq>'2009’)… else ….
第四篇:计算机系统安全性分析
计算机系统安全性分析
摘要:引言
随着计算机科学技术的迅速发展和广泛应用,计算机系统的安全问题已成为人们十分关注的重要课题。对计算机系统的威胁和攻击主要有两类:一类是对计算机系统实体的威胁和攻击; 一类是对信息的威胁和攻击。计算机犯罪和计算机病毒则包含了对实体和信息两个方面的威胁和攻击。计算机系统实体所面临的威胁和攻击主要指各种自然灾害、场地和环境因素的影响、战争破坏和损失、设备故障、人为破坏、各种媒体设备的损坏和丢失。对实体的威胁和攻击,不仅造成国家财产的严重损失,而且会造成信息的泄漏和破坏。因此,对计算机系统实体的安全保护是防止对信息威胁和攻击的有力措施。对信息的威胁和攻击主要有两种方式: 一种是信息泄漏,一种是信息破坏。信息泄漏是指故意或偶然地侦收、截获、窃取、分析、收集到系统中的信息,特别是机密信息和敏感信息,造成泄密事件。信息的破坏是指由于偶然事故或人为因素破坏信息的完整性、正确性和可用性,如各种软硬件的偶然故障,环境和自然因素的影响以及操作失误造成的信息破坏,尤其是计算机犯罪和计算机病毒造成信息的修改、删除或破坏,将导致系统资源被盗或被非法使用,甚至使系统瘫痪。
2、计算机系统安全概述
计算机系统(computer system)也称计算机信息系统(Computer Information System),是由计算机及其相关的和配套的设备、设施(含网络)构成的,并按一定的应用目标和规则对信息进行采集、加工、存储、传输、检索等处理的人机系统。计算机系统安全(computer system security)中的“安全”一词是指将服务与资源的脆弱性降到最低限度。脆弱性是指计算机系统的任何弱点。
国际标准化组织(ISO)将“计算机安全”定义为:“为数据处理系统建立和采取的技术和管理的安全保护,保护计算机硬件、软件数据不因偶然和恶意的原因而遭到破坏、更改和泄露。”此概念偏重于静态信息保护。也有人将“计算机安全”定义为:“计算机的硬件、软件和数据受到保护,不因偶然和恶意的原因而遭到破坏、更改和泄露,系统连续正常运行。”该定义着重于动态意义描述。
在美国国家信息基础设施(NII)的文献中,给出了安全的五个属性:可用性、可靠性、完整性、保密性和不可抵赖性。这五个属性适用于国家信息基础设施的教育、娱乐、医疗、运输、国家安全、电力供给及分配、通信等广泛领域。这五个属性定义如下:
可用性(Availability):得到授权的实体在需要时可访问资源和服务。可用性是指无论何时,只要用户需要,信息系统必须是可用的,也就是说信息系统不能拒绝服务。网络最基本的功能是向用户提供所需的信息和通信服务,而用户的通信要求是随机的,多方面的(话音、数据、文字和图像等),有时还要求时效性。网络必须随时满足用户通信的要求。攻击者通常采用占用资源的手段阻碍授权者的工作。可以使用访问控制机制,阻止非授权用户进入网络,从而保证网络系统的可用性。增强可用性还包括如何有效地避免因各种灾害(战争、地震等)造成的系统失效。
可靠性(Reliability):可靠性是指系统在规定条件下和规定时间内、完成规定功能的概率。可靠性是网络安全最基本的要求之一,网络不可靠,事故不断,也就谈不上网络的安全。目前,对于网络可靠性的研究基本上偏重于硬件可靠性方面。研制高可靠性元器件设备,采取合理的冗余备份措施仍是最基本的可靠性对策,然而,有许多故障和事故,则与软件可靠
性、人员可靠性和环境可靠性有关。
完整性(Integrity):信息不被偶然或蓄意地删除、修改、伪造、乱序、重放、插入等破坏的特性。只有得到允许的人才能修改实体或进程,并且能够判别出实体或进程是否已被篡改。即信息的内容不能为未授权的第三方修改。信息在存储或传输时不被修改、破坏,不出现信息包的丢失、乱序等。
保密性(Confidentiality):保密性是指确保信息不暴露给未授权的实体或进程。即信息的内容不会被未授权的第三方所知。这里所指的信息不但包括国家秘密,而且包括各种社会团体、企业组织的工作秘密及商业秘密,个人的秘密和个人私密(如浏览习惯、购物习惯)。防止信息失窃和泄露的保障技术称为保密技术。
不可抵赖性(Non-Repudiation):也称作不可否认性。不可抵赖性是面向通信双方(人、实体或进程)信息真实同一的安全要求,它包括收、发双方均不可抵赖。一是源发证明,它提供给信息接收者以证据,这将使发送者谎称未发送过这些信息或者否认它的内容的企图不能得逞;二是交付证明,它提供给信息发送者以证明这将使接收者谎称未接收过这些信息或者否认它的内容的企图不能得逞。影响计算机系统安全问题分析
这里我们只考虑从计算机用户角度来讲的计算机系统信息安全隐患。它大致有如下几个方面:
3.1计算机网络病毒
计算机网络病毒除了具有传统病毒的破坏性特点外。还具有网络特性。随着互联网的广泛应用。使得其传播途径更广、速度更快.危害也更大。计算机网络病毒主要有:宏病毒、网页脚本病毒、蠕虫病毒。其中蠕虫病毒与其他病毒不同的是其传播具有主动性。它会主动扫描网络上主机操作系统和一些网络服务的漏洞。利用这些漏洞感染这些主机。
3.2特洛伊木马
许多人也将它归为计算机病毒一类。但它与计算机病毒又有较大的区别。计算机病毒从来不在宿主代码之外独立。而总是把自己嵌入宿主代码,从而成为恶意代码。木马则是一个独立运行的程序。它一般由一个客户端和一个服务端两部分构成,服务器端就安装在受害者的机器上,并注册成为一种“服务”。然后从远程控制你的机器等等。而且这种攻击往往发生在受害者毫不知情的状况下。所以特洛伊木马的危害不亚于病毒。
3.3黑客恶意攻击
不管黑客攻击的是哪种类型的目标,其采用的攻击手段和过程都具有一定的共性。一般攻击大体有如下几个步骤:对目标系统安全脆弱性进行扫描与分析;找到漏洞入口;执行攻击程序;获得管理员权限;放置木马后门;清除痕迹。
4.计算机系统安全管理对策
计算机系统的安全性和可靠性,来源于安全策略的多样性和安全技术的先进性。计算机技术是当今发展最快的技术之一,对于计算机系统的安全性,也要根据计算机系统的发展 不断完善和改进,策略要不断求变,技术要不断创新,特别是随着计算机网络在社会的各个方面的延伸。进入网络的手段越来越多,越来越方便,因此,对于计算机系统来自网络方面 的安全威胁,更是安全防范的重中之重。特别是对予各单位的一些要害部门。必须做到领导重视,制度健全,措施得力,大力加强工作人员的责任心和防范意识。自觉执行各项安全制度,采用先进的技术和产品,构造全方位的防御机制,使计算机系统在理想的状态下稳定可靠地运行。
4.1建立健全安全管理制度
建立健全安全管理制度是安全管理的重要前提。标准化的安全管理,能克服传统管理中凭借个人的主观意志驱动管理模式。不管人员如何变化,先进的管理方法和经验可以得到 很好的继承。根据本单位的实际情况和所采用的技术条件,参照有关的法规、条例和其他单位好的经验,制定出切实可行又比较全面的各类安全管理制度。这些制度应包括:重要数据备份制度、信息数据恢复策略、应用程序使用权限管理制度、用户账户管理制度、计算机设备使用管理制度、计算机网络安全管理制度、密钥安全管理制度、计算机病毒防治管理制度等。
4.2做好防御病毒和存储权限设置
防御病毒首先要加强计算机内部使用人员的教育,养成良好的安全上网习惯和安全意识。不随便下载和使用来历不明的计算机软件和文件,选择安装杀毒软件、后门及木马检测和清除软件。以及防火墙软件,在局域网中使用网络版杀毒软件。计算机采用口令来控制授权访问,首先口令必须符合复杂口令规则、定期更换口令、不同的人员设置不同的访问权限。我们需要对系统的所有资源进行权限控制,权限控制的目标就是对应用系统的所有对象资源和数据资源进行权限控制。比如应用系统的功能菜单、各个界面的按钮、数据显示的列及 各种行级数据进行权限的操控。
4.3做好防御黑客的策略
防御黑客的策略是对计算机系统以及整个网络系统实施分层次、多级别的防护。包括检测、告警和修复等应急功能的实时策略。主要有:一是防火墙技术,防火墙构成了系统对外防御的第一道防线。防火墙是用来隔离被保护的内部网络。明确定义网络的边界和服务,完成授权、访问控制以及安全审计的功能。它是分离器、限制器,也是分析器。它有效地监控了内部网和Intemet之间的任何活动,保证了内部网络的安全。防火墙技术可根据防范的方式和侧重点的不同而分为很多种类型。但总体来讲可分为二大类:分组过滤、应用代理。防火墙很难防范来自于网络内部的攻击以及病毒的威胁,基于网络主机的操作系统安全和物理安会措施。按照级别从低到高,分别是主机系统的物理安全、操作系统的内核安全、系统服务安全、应用服务安全和文件系统安全:主机安全检查和漏洞修补以及系统备份安全作为辅助安全措施。主要防范部分突破防火墙以及从内部发起的攻击。二是入侵检测技术。入侵检测技术是为保证计算机系统的安全而设计与配置的,是一种能够及时发现并报告系统中未授权或异常现象的技术,也是用于检测计算机网络中违反安全策略行为的技术。入侵检测系统能够识别出任何不希望有的活动,这种活动可能来自于网络外部和内部。入侵检测系统的应用。能使在入侵攻击对系统发生危害前,检测到入侵攻击,并利用报警与防护系统驱逐入侵攻击。在入侵攻击过程中,能减少入侵攻击所造成的损失。在被入侵攻击后,收集入侵攻击的相关信息,作为防范系统的知识。添加到知识库内,以增强系统的防范能力。
4.4关于数据备份策略
建议在计算机中安装光盘刻录机,将一些不再修改的重要数据,直接刻录在光盘上,分别存放在不同地点:一些还需修改的数据,可通过U盘或移动硬盘,分别存放在办公室或家庭中的不同计算机中;对于有局域网的单位用户。一些重要但不需要保密的数据,可分别存放在本地计算机和局域网服务器中;对于一些较小的数据文件。也可压缩后保存在自己的邮箱中。数据备份的要点,一是要备份多份,分别存放在不同地点:二是备份要及时更新,不可存在侥幸心理,否则,一旦造成损失。后悔莫及。
4.5关于信息数据的恢复策略
只要及时做好了备份,数据的恢复非常简单。由于备份数据时的文件名可能与原文件名相同,所以在恢复时一定要注意,不要将被破坏的数据覆盖完整的数据:对于没有做备份的 数据。也可以通过一些工具软件进行部分恢复。但操作起来要复杂一些。不是一般用户能做的。
4.6密钥安全管理制度
在该制度的制定中,主要应考虑本单位的一些重要账户和密码的安全。这砦重要的账户和密码不应集中在某个人手中,而应该有一套严格的密钥安全管理办法和应急措施。
第五篇:心得总结:Java性能优化技巧集锦
心得总结:Java性能优化技巧集锦
一、通用篇
“通用篇”讨论的问题适合于大多数Java应用。
1.1 不用new关键词创建类的实例
用new关键词创建类的实例时,构造函数链中的所有构造函数都会被自动调用。但如果一个对象实现了Cloneable接口,我们可以调用它的clone()方法。clone()方法不会调用任何类构造函数。
在使用设计模式(Design Pattern)的场合,如果用Factory模式创建对象,则改用clone()方法创建新的对象实例非常简单。例如,下面是Factory模式的一个典型实现: public static Credit getNewCredit(){ return new Credit();}
改进后的代码使用clone()方法,如下所示: private static Credit BaseCredit = new Credit();public static Credit getNewCredit(){ return(Credit)BaseCredit.clone();}
上面的思路对于数组处理同样很有用。
1.2 使用非阻塞I/O
版本较低的JDK不支持非阻塞I/O API。为避免I/O阻塞,一些应用采用了创建大量线程的办法(在较好的情况下,会使用一个缓冲池)。这种技术可以在许多必须支持并发I/O流的应用中见到,如Web服务器、报价和拍卖应用等。然而,创建Java线程需要相当可观的开销。
JDK 1.4引入了非阻塞的I/O库(java.nio)。如果应用要求使用版本较早的JDK,在这里有一个支持非阻塞I/O的软件包。
请参见Sun中国网站的《调整Java的I/O性能》。
1.3 慎用异常
异常对性能不利。抛出异常首先要创建一个新的对象。Throwable接口的构造函数调用名为fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法检查堆栈,收集调用跟踪信息。只要有异常被抛出,VM就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。
异常只能用于错误处理,不应该用来控制程序流程。
1.4 不要重复初始化变量
默认情况下,调用类的构造函数时,Java会把变量初始化成确定的值:所有的对象被设置成null,整数变量(byte、short、int、long)设置成0,float和 double变量设置成0.0,逻辑值设置成false。当一个类从另一个类派生时,这一点尤其应该注意,因为用new关键词创建一个对象时,构造函数链中的所有构造函数都会被自动调用。
1.5 尽量指定类的final修饰符
带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止了人们覆盖length()方法。
另外,如果指定一个类为final,则该类所有的方法都是final。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50%。
1.6 尽量使用局部变量
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。另外,依赖于具体的编译器/JVM,局部变量还可能得到进一步优化。请参见《尽可能使用堆栈变量》。
1.7 乘法和除法
考虑下面的代码:
for(val = 0;val < 100000;val +=5){ alterX = val * 8;myResult = val * 2;}
用移位操作替代乘法操作可以极大地提高性能。下面是修改后的代码:
for(val = 0;val < 100000;val += 5){ alterX = val << 3;myResult = val << 1;}
修改后的代码不再做乘以8的操作,而是改用等价的左移3位操作,每左移1位相当于乘以2。相应地,右移1位操作相当于除以2。值得一提的是,虽然移位操作速度快,但可能使代码比较难于理解,所以最好加上一些注释。
二、J2EE篇
前面介绍的改善性能技巧适合于大多数Java应用,接下来要讨论的问题适合于使用JSP、EJB或JDBC的应用。
2.1 使用缓冲标记
一些应用服务器加入了面向JSP的缓冲标记功能。例如,BEA的WebLogic Server从6.0版本开始支持这个功能,Open Symphony工程也同样支持这个功能。JSP缓冲标记既能够缓冲页面片断,也能够缓冲整个页面。当JSP页面执行时,如果目标片断已经在缓冲之中,则生成该片断的代码就不用再执行。页面级缓冲捕获对指定URL的请求,并缓冲整个结果页面。对于购物篮、目录以及门户网站的主页来说,这个功能极其有用。对于这类应用,页面级缓冲能够保存页面执行的结果,供后继请求使用。
对于代码逻辑复杂的页面,利用缓冲标记提高性能的效果比较明显;反之,效果可能略逊一筹。
请参见《用缓冲技术提高JSP应用的性能和稳定性》。
2.2 始终通过会话Bean访问实体Bean
直接访问实体Bean不利于性能。当客户程序远程访问实体Bean时,每一个get方法都是一个远程调用。访问实体Bean的会话Bean是本地的,能够把所有数据组织成一个结构,然后返回它的值。
用会话Bean封装对实体Bean的访问能够改进事务管理,因为会话Bean只有在到达事务边界时才会提交。每一个对get方法的直接调用产生一个事务,容器将在每一个实体Bean的事务之后执行一个“装入-读取”操作。
一些时候,使用实体Bean会导致程序性能不佳。如果实体Bean的唯一用途就是提取和更新数据,改成在会话Bean之内利用JDBC访问数据库可以得到更好的性能。
2.3 选择合适的引用机制
在典型的JSP应用系统中,页头、页脚部分往往被抽取出来,然后根据需要引入页头、页脚。当前,在JSP页面中引入外部资源的方法主要有两种:include指令,以及include动作。
include指令:例如<%@ include file=“copyright.html” %>。该指令在编译时引入指定的资源。在编译之前,带有include指令的页面和指定的资源被合并成一个文件。被引用的外部资源在编译时就确定,比运行时才确定资源更高效。
include动作:例如
2.4 在部署描述器中设置只读属性
实体Bean的部署描述器允许把所有get方法设置成“只读”。当某个事务单元的工作只包含执行读取操作的方法时,设置只读属性有利于提高性能,因为容器不必再执行存储操作。
2.5 缓冲对EJB Home的访问
EJB Home接口通过JNDI名称查找获得。这个操作需要相当可观的开销。JNDI查找最好放入Servlet的init()方法里面。如果应用中多处频繁地出现EJB访问,最好创建一个EJBHomeCache类。EJBHomeCache类一般应该作为singleton实现。
2.6 为EJB实现本地接口
本地接口是EJB 2.0规范新增的内容,它使得Bean能够避免远程调用的开销。请考虑下面的代码。PayBeanHome home =(PayBeanHome)javax.rmi.PortableRemoteObject.narrow(ctx.lookup(“PayBeanHome”), PayBeanHome.class);PayBean bean =(PayBean)javax.rmi.PortableRemoteObject.narrow(home.create(), PayBean.class);
第一个语句表示我们要寻找Bean的Home接口。这个查找通过JNDI进行,它是一个RMI调用。然后,我们定位远程对象,返回代理引用,这也是一个 RMI调用。第二个语句示范了如何创建一个实例,涉及了创建IIOP请求并在网络上传输请求的stub程序,它也是一个RMI调用。
要实现本地接口,我们必须作如下修改:
方法不能再抛出java.rmi.RemoteException异常,包括从RemoteException派生的异常,比如 TransactionRequiredException、TransactionRolledBackException和 NoSuchObjectException。EJB提供了等价的本地异常,如TransactionRequiredLocalException、TransactionRolledBackLocalException和NoSuchObjectLocalException。
所有数据和返回值都通过引用的方式传递,而不是传递值。
本地接口必须在EJB部署的机器上使用。简而言之,客户程序和提供服务的组件必须在同一个JVM上运行。
如果Bean实现了本地接口,则其引用不可串行化。
请参见《用本地引用提高EJB访问效率》。
软件资讯 > 开发特区 > 开发语言 > Java
2006年05月11日 作者:songxin 责任编辑:xietaoming
文章导读:分通用篇、J2EE篇、GUI篇三部分介绍Java性能优化技巧。
2.7 生成主键
在EJB之内生成主键有许多途径,下面分析了几种常见的办法以及它们的特点。
利用数据库内建的标识机制(SQL Server的IDENTITY或Oracle的SEQUENCE)。这种方法的缺点是EJB可移植性差。
由实体Bean自己计算主键值(比如做增量操作)。它的缺点是要求事务可串行化,而且速度也较慢。
利用NTP之类的时钟服务。这要求有面向特定平台的本地代码,从而把Bean固定到了特定的OS之上。另外,它还导致了这样一种可能,即在多CPU的服务器上,同一个毫秒之内生成了两个主键。
借鉴Microsoft的思路,在Bean中创建一个GUID。然而,如果不求助于JNI,Java不能确定网卡的MAC地址;如果使用JNI,则程序就要依赖于特定的OS。
还有其他几种办法,但这些办法同样都有各自的局限。似乎只有一个答案比较理想:结合运用RMI和JNDI。先通过RMI注册把RMI远程对象绑定到JNDI树。客户程序通过JNDI进行查找。下面是一个例子: public class keyGenerator extends UnicastRemoteObject implements Remote { private static long KeyValue = System.currentTimeMillis();public static synchronized long getKey()throws RemoteException { return KeyValue++;}
2.8 及时清除不再需要的会话
为了清除不再活动的会话,许多应用服务器都有默认的会话超时时间,一般为30分钟。当应用服务器需要保存更多会话时,如果内存容量不足,操作系统会把部分内存数据转移到磁盘,应用服务器也可能根据“最近最频繁使用”(Most Recently Used)算法把部分不活跃的会话转储到磁盘,甚至可能抛出“内存不足”异常。在大规模系统中,串行化会话的代价是很昂贵的。当会话不再需要时,应当及时调用HttpSession.invalidate()方法清除会话。HttpSession.invalidate()方法通常可以在应用的退出页面调用。
2.9 在JSP页面中关闭无用的会话
对于那些无需跟踪会话状态的页面,关闭自动创建的会话可以节省一些资源。使用如下page指令: <%@ page session=“false”%>
2.10 Servlet与内存使用
许多开发者随意地把大量信息保存到用户会话之中。一些时候,保存在会话中的对象没有及时地被垃圾回收机制回收。从性能上看,典型的症状是用户感到系统周期性地变慢,却又不能把原因归于任何一个具体的组件。如果监视JVM的堆空间,它的表现是内存占用不正常地大起大落。
解决这类内存问题主要有二种办法。第一种办法是,在所有作用范围为会话的Bean中实现HttpSessionBindingListener接口。这样,只要实现valueUnbound()方法,就可以显式地释放Bean使用的资源。
另外一种办法就是尽快地把会话作废。大多数应用服务器都有设置会话作废间隔时间的选项。另外,也可以用编程的方式调用会话的 setMaxInactiveInterval()方法,该方法用来设定在作废会话之前,Servlet容器允许的客户请求的最大间隔时间,以秒计。
2.11 HTTP Keep-Alive
Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。市场上的大部分Web服务器,包括iPlanet、IIS和Apache,都支持HTTP Keep-Alive。对于提供静态内容的网站来说,这个功能通常很有用。但是,对于负担较重的网站来说,这
里存在另外一个问题:虽然为客户保留打开的连接有一定的好处,但它同样影响了性能,因为在处理暂停期间,本来可以释放的资源仍旧被占用。当Web服务器和应用服务器在同一台机器上运行时,Keep-Alive功能对资源利用的影响尤其突出。
2.12 JDBC与Unicode
想必你已经了解一些使用JDBC时提高性能的措施,比如利用连接池、正确地选择存储过程和直接执行的SQL、从结果集删除多余的列、预先编译SQL语句,等等。
除了这些显而易见的选择之外,另一个提高性能的好选择可能就是把所有的字符数据都保存为Unicode(代码页13488)。Java以Unicode形式处理所有数据,因此,数据库驱动程序不必再执行转换过程。但应该记住:如果采用这种方式,数据库会变得更大,因为每个Unicode字符需要2个字节存储空间。另外,如果有其他非Unicode的程序访问数据库,性能问题仍旧会出现,因为这时数据库驱动程序仍旧必须执行转换过程。
2.13 JDBC与I/O
如果应用程序需要访问一个规模很大的数据集,则应当考虑使用块提取方式。默认情况下,JDBC每次提取32行数据。举例来说,假设我们要遍历一个5000 行的记录集,JDBC必须调用数据库157次才能提取到全部数据。如果把块大小改成512,则调用数据库的次数将减少到10次。
在一些情形下这种技术无效。例如,如果使用可滚动的记录集,或者在查询中指定了FOR UPDATE,则块操作方式不再有效。
2.14 内存数据库
许多应用需要以用户为单位在会话对象中保存相当数量的数据,典型的应用如购物篮和目录等。由于这类数据可以按照行/列的形式组织,因此,许多应用创建了庞大的Vector或HashMap。在会话中保存这类数据极大地限制了应用的可伸缩性,因为服务器拥有的内存至少必须达到每个会话占用的内存数量乘以并发用户最大数量,它不仅使服务器价格昂贵,而且垃圾收集的时间间隔也可能延长到难以忍受的程度。
一些人把购物篮/目录功能转移到数据库层,在一定程度上提高了可伸缩性。然而,把这部分功能放到数据库层也存在问题,且问题的根源与大多数关系数据库系统的体系结构有关。对于关系数据库来说,运行时的重要原则之一是确保所有的写入操作稳定、可靠,因而,所有的性能问题都与物理上把数据写入磁盘的能力有关。关系数据库力图减少I/O操作,特别是对于读操作,但实现该目标的主要途径只是执行一套实现缓冲机制的复杂算法,而这正是数据库层第一号性能瓶颈通常总是 CPU的主要原因。
一种替代传统关系数据库的方案是,使用在内存中运行的数据库(In-memory Database),例如TimesTen。内存数据库的出发点是允许数据临时地写入,但这些数据不必永久地保存到磁盘上,所有的操作都在内存中进行。这样,内存数据库不需要复杂的算法来减少I/O操作,而且可以采用比较简单的加锁机制,因而速度很快。
三、GUI篇
这一部分介绍的内容适合于图形用户界面的应用(Applet和普通应用),要用到AWT或Swing。
3.1 用JAR压缩类文件
Java档案文件(JAR文件)是根据JavaBean标准压缩的文件,是发布JavaBean组件的主要方式和推荐方式。JAR档案有助于减少文件体积,缩短下载时间。例如,它有助于Applet提高启动速度。一个JAR文件可以包含一个或者多个相关的Bean以及支持文件,比如图形、声音、HTML 和其他资源。
要在HTML/JSP文件中指定JAR文件,只需在Applet标记中加入ARCHIVE = “name.jar”声明。
请参见《使用档案文件提高 applet 的加载速度》。
3.2 提示Applet装入进程
你是否看到过使用Applet的网站,注意到在应该运行Applet的地方出现了一个占位符?当Applet的下载时间较长时,会发生什么事情?最大的可能就是用户掉头离去。在这种情况下,显示一个Applet正在下载的信息无疑有助于鼓励用户继续等待。
下面我们来看看一种具体的实现方法。首先创建一个很小的Applet,该Applet负责在后台下载正式的Applet:
import java.applet.Applet;import java.applet.AppletStub;import java.awt.Label;import java.awt.Graphics;import java.awt.GridLayout;public class PreLoader extends Applet implements Runnable, AppletStub { String largeAppletName;Label label;public void init(){ // 要求装载的正式Applet largeAppletName = getParameter(“applet”);// “请稍等”提示信息
label = new Label(“请稍等...” + largeAppletName);add(label);} public void run(){ try { // 获得待装载Applet的类
Class largeAppletClass = Class.forName(largeAppletName);// 创建待装载Applet的实例
Applet largeApplet =(Applet)largeAppletClass.newInstance();// 设置该Applet的Stub程序 largeApplet.setStub(this);// 取消“请稍等”信息 remove(label);// 设置布局
setLayout(new GridLayout(1, 0));add(largeApplet);// 显示正式的Applet largeApplet.init();largeApplet.start();} catch(Exception ex){ // 显示错误信息
label.setText(“不能装入指定的Applet”);} // 刷新屏幕 validate();
} public void appletResize(int width, int height){ // 把appletResize调用从stub程序传递到Applet resize(width, height);} }
编译后的代码小于2K,下载速度很快。代码中有几个地方值得注意。首先,PreLoader实现了AppletStub接口。一般地,Applet从调用者判断自己的codebase。在本例中,我们必须调用setStub()告诉Applet到哪里提取这个信息。另一个值得注意的地方是,AppletStub接口包含许多和Applet类一样的方法,但appletResize()方法除外。这里我们把对appletResize()方法的调用传递给了resize()方法。
3.3 在画出图形之前预先装入它
ImageObserver接口可用来接收图形装入的提示信息。ImageObserver接口只有一个方法imageUpdate(),能够用一次repaint()操作在屏幕上画出图形。下面提供了一个例子。public boolean imageUpdate(Image img, int flags, int x, int y, int w, int h){ if((flags & ALLBITS)!=0 { repaint();} else if(flags &(ERROR |ABORT))!= 0){ error = true;// 文件没有找到,考虑显示一个占位符 repaint();} return(flags &(ALLBITS | ERROR| ABORT))== 0;}
当图形信息可用时,imageUpdate()方法被调用。如果需要进一步更新,该方法返回true;如果所需信息已经得到,该方法返回false。
3.4 覆盖update方法
update()方法的默认动作是清除屏幕,然后调用paint()方法。如果使用默认的update()方法,频繁使用图形的应用可能出现显示闪烁现象。要避免在paint()调用之前的屏幕清除操作,只需按照如下方式覆盖update()方法:
public void update(Graphics g){ paint(g);}
更理想的方案是:覆盖update(),只重画屏幕上发生变化的区域,如下所示: public void update(Graphics g){ g.clipRect(x, y, w, h);paint(g);}
3.5 延迟重画操作
对于图形用户界面的应用来说,性能低下的主要原因往往可以归结为重画屏幕的效率低下。当用户改变窗口大小或者滚动一个窗口时,这一点通常可以很明显地观察到。改变窗口大小或者滚动屏幕之类的操作导致重画屏幕事件大量地、快速地生成,甚至超过了相关代码的执行速度。对付这个问题最好的办法是忽略所有“迟到” 的事件。
建议在这里引入一个数毫秒的时差,即如果我们立即接收到了另一个重画事件,可以停止处理当前事件转而处理最后一个收到的重画事件;否则,我们继续进行当前的重画过程。
如果事件要启动一项耗时的工作,分离出一个工作线程是一种较好的处理方式;否则,一些部件可能被“冻结”,因为每次只能处理一个事件。下面提供了一个事件处理的简单例子,但经过扩展后它可以用来控制工作线程。
public static void runOnce(String id, final long milliseconds){ synchronized(e_queue){ // e_queue: 所有事件的集合 if(!e_queue.containsKey(id)){ e_queue.put(token, new LastOne());} } final LastOne lastOne =(LastOne)e_queue.get(token);final long time = System.currentTimeMillis();// 获得当前时间 lastOne.time = time;(new Thread(){public void run(){ if(milliseconds > 0){ try {Thread.sleep(milliseconds);} // 暂停线程 catch(Exception ex){} } synchronized(lastOne.running){ // 等待上一事件结束 if(lastOne.time!= time)// 只处理最后一个事件 return;} }}).start();} private static Hashtable e_queue = new Hashtable();private static class LastOne { public long time=0;public Object running = new Object();}
3.6 使用双缓冲区
在屏幕之外的缓冲区绘图,完成后立即把整个图形显示出来。由于有两个缓冲区,所以程序可以来回切换。这样,我们可以用一个低优先级的线程负责画图,使得程序能够利用空闲的CPU时间执行其他任务。下面的伪代码片断示范了这种技术。Graphics myGraphics;Image myOffscreenImage = createImage(size().width, size().height);
Graphics offscreenGraphics = myOffscreenImage.getGraphics();offscreenGraphics.drawImage(img, 50, 50, this);myGraphics.drawImage(myOffscreenImage, 0, 0, this);
3.7 使用BufferedImage
Java JDK 1.2使用了一个软显示设备,使得文本在不同的平台上看起来相似。为实现这个功能,Java必须直接处理构成文字的像素。由于这种技术要在内存中大量地进行位复制操作,早期的JDK在使用这种技术时性能不佳。为解决这个问题而提出的Java标准实现了一种新的图形类型,即BufferedImage。
BufferedImage子类描述的图形带有一个可访问的图形数据缓冲区。一个BufferedImage包含一个ColorModel和一组光栅图形数据。这个类一般使用RGB(红、绿、蓝)颜色模型,但也可以处理灰度级图形。它的构造函数很简单,如下所示:
public BufferedImage(int width, int height, int imageType)
ImageType允许我们指定要缓冲的是什么类型的图形,比如5-位RGB、8-位RGB、灰度级等。
3.8 使用VolatileImage
许多硬件平台和它们的操作系统都提供基本的硬件加速支持。例如,硬件加速一般提供矩形填充功能,和利用CPU完成同一任务相比,硬件加速的效率更高。由于硬件加速分离了一部分工作,允许多个工作流并发进行,从而缓解了对CPU和系统总线的压力,使得应用能够运行得更快。利用VolatileImage可以创建硬件加速的图形以及管理图形的内容。由于它直接利用低层平台的能力,性能的改善程度主要取决于系统使用的图形适配器。VolatileImage的内容随时可能丢失,也即它是“不稳定的(volatile)”。因此,在使用图形之前,最好检查一下它的内容是否丢失。VolatileImage有两个能够检查内容是否丢失的方法: public abstract int validate(GraphicsConfiguration gc);public abstract Boolean contentsLost();
每次从VolatileImage对象复制内容或者写入VolatileImage时,应该调用validate()方法。contentsLost()方法告诉我们,自从最后一次validate()调用之后,图形的内容是否丢失。
虽然VolatileImage是一个抽象类,但不要从它这里派生子类。VolatileImage应该通过
Component.createVolatileImage()或者 GraphicsConfiguration.createCompatibleVolatileImage()方法创建。
3.9 使用Window Blitting
进行滚动操作时,所有可见的内容一般都要重画,从而导致大量不必要的重画工作。许多操作系统的图形子系统,包括WIN32 GDI、MacOS和X/Windows,都支持Window Blitting技术。Window Blitting技术直接在屏幕缓冲区中把图形移到新的位置,只重画新出现的区域。要在Swing应用中使用Window Blitting技术,设置方法如下: setScrollMode(int mode);
在大多数应用中,使用这种技术能够提高滚动速度。只有在一种情形下,Window Blitting会导致性能降低,即应用在后台进行滚动操作。如果是用户在滚动一个应用,那么它总是在前台,无需担心任何负面影响。