尽管Java Swing框架的性能在最新的JDK版本中有了很大的改进,由于对Swing的线程概念认识不足,也有可能写出速度很慢的程序,下边介绍一下自己开发 Swing Rich Client程序的心得体会,与大家共享:
1.要学会使用SwingWorker,当执行查询数据库,连接网络,或长时间的计算,这些代码应该放在doInBackground()方法, 而完成这些后需要更新GUI应该把代码放在done()方法。JDK 1.6的swing包中内置有SwingWorker类,如果你还在使用JDK1.5版本,可以从这里下载 https://swingworker.dev.java.net/,如果使用更早期的版本,如JDK1.4,可以从这里下载http://java.sun.com/products/jfc/tsc/articles/threads/src/SwingWorker.java,如果 你想在JDK1.4或者之前使用和JDK1.6的接口有限兼容的版本,以便以后升级,可以使用我自己修改的一个版本:
import javax.swing.SwingUtilities;
/**
* Modified this version SwingWorker to use the same
* interface with the JDK 1.6 SwingWorker.
* <p>
* public construct(); ---> protected doInBackground();
* finished(); ---> done();
* start(); ---> execute();
*/
/**
* This is the 3rd version of SwingWorker (also known as
* SwingWorker 3),an abstract class that you subclass to
* perform GUI-related work in a dedicated thread.For
* instructions on using this class,see:
*
* http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html
*
* Note that the API changed slightly in the 3rd version:
* You must now invoke start()on the SwingWorker after
* creating it.
*/
public abstract class SwingWorker {
private Object value; // see getValue(),setValue()
private Thread thread;
/**
* Class to maintain reference to current worker thread
* under separate synchronization control.
*/
private static class ThreadVar {
private Thread thread;
ThreadVar(Thread t){thread = t; }
synchronized Thread get() {return thread; }
synchronized void clear() {thread = null; }
}
private ThreadVar threadVar;
/**
* Get the value produced by the worker thread,or null if it
* hasn't been constructed yet.
*/
protected synchronized Object getValue() {
return value;
}
/**
* Set the value produced by worker thread
*/
private synchronized void setValue(Object x) {
value = x;
}
private Exception e;
private synchronized void setException(Exception e) {
this.e = e;
}
private synchronized Exception getException() {
return e;
}
/**
* Compute the value to be returned by the <code>get</code> method.
*/
protected abstract Object doInBackground() throws Exception;
/**
* Called on the event dispatching thread (not on the worker thread)
* after the <code>construct</code> method has returned.
*/
protected void done() {
}
/**
* A new method that interrupts the worker thread. Call this method
* to force the worker to stop what it's doing.
*/
public void interrupt() {
Thread t = threadVar.get();
if(t != null) {
t.interrupt();
}
threadVar.clear();
}
/**
* Return the value created by the <code>construct</code> method.
* Returns null if either the constructing thread or the current
* thread was interrupted before a value was produced.
*
* @return the value created by the <code>construct</code> method
*/
public Object get() throws Exception {
while (true) {
Thread t = threadVar.get();
if(t == null) {
if(getException() != null) {
throw getException();
}
return getValue();
}
try {
t.join();
}
catch (InterruptedException e) {
Thread.currentThread().interrupt(); // propagate
return null;
}
}
}
/**
* Start a thread that will call the <code>construct</code> method
* and then exit.
*/
public SwingWorker() {
final Runnable doFinished = new Runnable() {
public void run() {done(); }
};
Runnable doConstruct = new Runnable() {
public void run() {
try {
setValue(doInBackground());
} catch(Exception e) {
setException(e);
}
finally {
threadVar.clear();
}
SwingUtilities.invokeLater(doFinished);
}
};
Thread t = new Thread(doConstruct);
t.setPriority(Thread.NORM_PRIORITY - 2);
threadVar = new ThreadVar(t);
}
/**
* Start the worker thread.
*/
public void execute() {
Thread t = threadVar.get();
if (t != null) {
t.start();
}
}
}
(1)GraphicsDevice.getDisplayModes()方法,如果使用Java写2D游戏,应该注意这个方法,最好 不要先调用这个方法,如果你想做全屏游戏,可以先设置默认的屏幕显示模式,例如:new DisplayMode(800, 600,32,60),在catch(IllegalArgumentException)后从 GraphicsDevice.getDisplayModes()方法查询适合你的游戏的显示模式,再进行设置。
(2)GraphicsEnvironment.getAllFonts() 方法和GraphicsEnvironment.getAvailableFontFamilyNames()方法,这两个方法因为要读字体文件夹,所以耗时很长,影响性能,一般可以通过后台线程调用这些方法后,更新界面。
(3)PrinterJob.getPrinterJob()和PrinterJob.defaultPage()方法,这两个方法在 设置有网络打印机的电脑运行非常慢,因为需要查找网络打印机,而getPrinterJob() 方法更极端,每次调用时都要重新查找网络打印机,所以最好调用一次之后缓存getPrinterJob() 的引用。