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影响性能,希望能和您共同讨论。

你可能感兴趣的:(Java程序性能之一)