SwingWorker單線程規(guī)則
SwingAPI的設計目標是強大、靈活和易用。非凡地,我們希望能讓程序員們方便地建立新的Swing組件,不論是從頭開始還是通過擴展我們所提供的一些組件。出于這個目的,我們不要求Swing組件支持多線程訪問。相反,我們向組件發(fā)送請求并在單一線程中執(zhí)行請求。本文討論線程和Swing組件。目的不僅是為了幫助你以線程安全的方式使用SwingAPI,而且解釋了我們?yōu)槭裁磿x擇現在這樣的線程方案。本文包括以下內容:
單線程規(guī)則:SwingWorker單線程在同一時刻僅能被一個線程所訪問。一般來說,這個線程是事件派發(fā)線程。規(guī)則的例外:有些操作保證是線程安全的。事件分發(fā):假如你需要從事件處理或繪制代碼以外的地方訪問UI,那么你可以使用SwingUtilities 類的invokeLater要求在事件派發(fā)線程中執(zhí)行某些代碼。這個方法會立即返回,不會等待代碼執(zhí)行完畢。invokeAndWait行為與 invokeLater類似,除了這個方法會等待代碼執(zhí)行完畢。一般地,你可以用invokeLater來代替這個方法。下面是一些使用這幾個API的例子。請同時參閱《TheJavaTutorial》中的“BINGOexample”,尤其是以下幾個類:CardWindow、ControlPane、Player和OverallStatusPane。
使用invokeLater方法你可以從任何線程調用invokeLater方法以請求事件派發(fā)線程運行特定代碼。你必須把要運行的代碼放到一個 Runnable對象的run方法中,并將此Runnable對象設為invokeLater的參數。invokeLater方法會立即返回,不等待事件派發(fā)線程執(zhí)行指定代碼。這是一個使用invokeLater方法的例子:
- RunnabledoWorkRunnable=newRunnable
- }
SwingUtilities.invokeLater; 使用invokeAndWait方法invokeAndWait方法和invokeLater方法很相似,除了invokeAndWait方法會等事件派發(fā)線程執(zhí)行了指定代碼才返回。在可能的情況下,你應該盡量用invokeLater來代替invokeAndWait。假如你真的要使用 invokeAndWait,請確保調用invokeAndWait的線程不會在調用期間持有任何其他線程可能需要的鎖。
這是一個使用invokeAndWait的例子:
- voidshowHelloThereDialogthrowsException
- }
- SwingUtilities.invokeAndWait;
- }
類似地,假設一個線程需要對GUI的狀態(tài)進行存取,比如文本域的內容,它的代碼可能類似這樣:
- voidprintTextField
- throwsException
- }
- SwingUtilities.invokeAndWait
- System.out.println
- }
假如你能避免使用線程,最好這樣做。線程可能難于使用,并使得程序的debug更困難。一般來說,對于嚴格意義下的GUI工作,線程是不必要的,比如對組件屬性的更新。不管怎么說,有時候線程是必要的。下列情況是使用線程的一些典型情況:執(zhí)行一項費時的任務而不必將事件派發(fā)線程鎖定。例子包括執(zhí)行大量計算的情況,會導致大量類被裝載的情況,和為網絡或磁盤I/O而阻塞的情況。重復地執(zhí)行一項操作,通常在兩次操作間間隔一個預定的時間周期。要等待來自客戶的消息。你可以使用兩個類來幫助你實現線程:SwingWorker:創(chuàng)建一個后臺線程來執(zhí)行費時的操作。Timer:創(chuàng)建一個線程來執(zhí)行或多次執(zhí)行某些代碼,在兩次執(zhí)行間間隔用戶定義的延遲。使用SwingWorker單線程在SwingWorker.java中實現,這個類并不包含在Java的任何發(fā)行版中,所以你必須單獨下載它。SwingWorker單線程做了所有實現一個后臺線程所需的骯臟工作。雖然許多程序都不需要后臺線程,后臺線程在執(zhí)行費時的操作時仍然是很有用的,它能提高程序的性能觀感。
【編輯推薦】