java性能优化:Java性能优化技巧集锦(2)



3、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网站WebSite注意到在应该运行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 PreLoader extends Applet implements Runnable, AppletStub {
String largeAppletName;
Label label;
public void init {
// 要求装载正式Applet
largeAppletName = getParameter("applet");
// “请稍等”提示信息
label = Label("请稍等..." + largeAppletName);
add(label);
}
public void run{
try {
// 获得待装载Applet
Class largeAppletClass = Class.forName(largeAppletName);
// 创建待装载Applet例子
Applet largeApplet = (Applet)largeAppletClass.Instance;
// 设置该AppletStub
largeApplet.Stub(this);
// 取消“请稍等”信息
remove(label);
// 设置布局
Layout( GridLayout(1, 0));
add(largeApplet);
// 显示正式Applet
largeApplet.init;
largeApplet.start;
}
catch (Exception ex) {
// 显示信息
label.Text("不能装入指定Applet");
}
// 刷新屏幕
validate;
}
public void appletResize( width, height) {
// 把appletResize从stub传递到Applet
resize(width, height);
}
}



编译后代码小于2K下载速度很快代码中有几个地方值得注意首先PreLoader实现了AppletStub接口般地Applet从者判断自己codebase在本例中我们必须Stub告诉Applet到哪里提取这个信息个值得注意地方是AppletStub接口包含许多和Applet类思路方法但appletResize思路方法除外这里我们把对appletResize思路方法传递给了resize思路方法

3.3 在画出图形的前预先装入它

ImageObserver接口可用来接收图形装入提示信息ImageObserver接口只有个思路方法imageUpdate能够用次repa操作在屏幕上画出图形下面提供了个例子


public boolean imageUpdate(Image img, flags, x, y, w, h) {
((flags & ALLBITS) !=0 {
repa;
}
(flags & (ERROR |ABORT )) != 0) {
error = true;
// 文件没有找到考虑显示个占位符
repa;
}
(flags & (ALLBITS | ERROR| ABORT)) 0;


}



当图形信息可用时imageUpdate思路方法被如果需要进步更新该思路方法返回true;如果所需信息已经得到该思路方法返回false

3.4 覆盖update思路方法

update思路方法默认动作是清除屏幕然后pa思路方法如果使用默认update思路方法频繁使用图形应用可能出现显示闪烁现象要避免在pa的前屏幕清除操作只需按照如下方式覆盖update思路方法:


public void update(Graphics g) {
pa(g);
}



更理想方案是:覆盖update只重画屏幕上发生变化区域如下所示:


public void update(Graphics g) {
g.clipRect(x, y, w, h);
pa(g);
}



3.5 延迟重画操作

对于图形用户界面应用来说性能低下主要原因往往可以归结为重画屏幕效率低下当用户改变窗口大小或者滚动个窗口时点通常可以很明显地观察到改变窗口大小或者滚动屏幕的类操作导致重画屏幕事件大量地、快速地生成甚至超过了相关代码执行速度对付这个问题最好办法是忽略所有“迟到”事件

建议在这里引入个数毫秒时差即如果我们立即接收到了另个重画事件可以停止处理当前事件转而处理最后个收到重画事件;否则我们继续进行当前重画过程

如果事件要启动项耗时工作分离出个工作线程是种较好处理方式;否则些部件可能被“冻结”每次只能处理个事件下面提供了个事件处理简单例子但经过扩展后它可以用来控制工作线程


public void runOnce(String id, final long milliseconds) {
synchronized(e_queue) { // e_queue: 所有事件集合
(!e_queue.containsKey(id)) {
e_queue.put(token, LastOne);
}
}
final LastOne lastOne = (LastOne) e_queue.get(token);
final long time = .currentTimeMillis; // 获得当前时间
lastOne.time = time;
( Thread {public void run {
(milliseconds > 0) {
try {Thread.sleep(milliseconds);} // 暂停线程
catch (Exception ex) {}
}
synchronized(lastOne.running) { // 等待上事件结束
(lastOne.time != time) // 只处理最后个事件
;
}
}}).start;
}
private Hashtable e_queue = Hashtable;
private LastOne {
public long time=0;
public Object running = 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 ( width, height, imageType)





ImageType允许我们指定要缓冲是什么类型图形比如5-位RGB、8-位RGB、灰度级等

3.8 使用VolatileImage

许多硬件平台和它们操作系统都提供基本硬件加速支持例如硬件加速般提供矩形填充功能和利用CPU完成同任务相比硬件加速效率更高由于硬件加速分离了部分工作允许多个工作流并发进行从而缓解了对CPU和系统总线压力使得应用能够运行得更快利用VolatileImage可以创建硬件加速图形以及管理图形内容由于它直接利用低层平台能力性能改善程度主要取决于系统使用图形适配器VolatileImage内容随时可能丢失也即它是“不稳定(volatile)”因此在使用图形的前最好检查下它内容是否丢失VolatileImage有两个能够检查内容是否丢失思路方法:


public abstract 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技术设置思路方法如下:


ScrollMode( mode);



在大多数应用中使用这种技术能够提高滚动速度只有在种情形下Window Blitting会导致性能降低即应用在后台进行滚动操作如果是用户在滚动个应用那么它总是在前台无需担心任何负面影响

4、补充资料

Tags:  性能优化 为提高性能而优化 java性能优化

延伸阅读

最新评论

发表评论