楼主 admin 发表于2010-10-9 14:39:30
Java程序性能之一

尽管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();

     }

  }

 }

这个修改的版本可以使用和JDK1.6相同的3个方法,分别是execute(),doInBackground(),done()。

2.避免程序开始就装载太多的类,在需要时创建类的实例,这样做能够加快程序的启动时间。

3.了解不同API的性能,这些API的性能不是显而易见的,而JavaDoc并没有给出明确地说明,下边有几个例子:

(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() 的引用。

(4)如果您发现有什么API影响性能,希望能和您共同讨论。