1. 程式人生 > >Java中事件分發執行緒

Java中事件分發執行緒

一 Swing線程基礎

一個Swing程式中一般有下面三種類型的執行緒:
    * 初始化執行緒(Initial Thread)
    * UI事件排程執行緒(EDT)
    * 任務執行緒(Worker Thread)
每個程式必須有一個main方法,這是程式的入口。該方法執行在初始化或啟動執行緒上。初始化執行緒讀取程式引數並初始化一些物件。在許多Swing程式中,該執行緒主要目的是啟動程式的圖形使用者介面(GUI)。一旦GUI啟動後,對於大多數事件驅動的桌面程式來說,初始化執行緒的工作就結束了。

Swing程式只有一個用EDT,該執行緒負責GUI元件的繪製和更新,通過呼叫程式的事件處理器來響應使用者互動。所有事件處理都是在EDT上進行的,程式同UI元件和其基本資料模型的互動只允許在EDT上進行,所有執行在EDT上的任務應該儘快完成,以便UI能及時響應使用者輸入。

Swing程式設計時應該注意以下三點:
1.從其他執行緒訪問UI元件及其事件處理器會導致介面更新和繪製錯誤。
2.在EDT上執行耗時任務會使程式失去響應,這會使GUI事件阻塞在佇列中得不到處理。
3.應使用獨立的任務執行緒來執行耗時計算或輸入輸出密集型任務,比如同資料庫通訊、訪問網站資源、讀寫大樹據量的檔案。
總之,任何干擾或延遲UI事件的處理只應該出現在獨立任務執行緒中;在初始化執行緒或任務執行緒同Swing元件或其預設資料模型進行的互動都是非執行緒安全性操作。

二 使用合適執行緒

初始化執行緒執行程式的main方法,該方法能處理許多工。但在典型的Swing程式中,其主要任務就是建立和執行應用程式的介面。建立UI的點,也就是程式開始將控制權轉交給UI時的點,往往是同EDT互動出現問題的第一個地方。

許多程式使用下面方法啟動介面,但這是錯誤的啟動UI介面的方法:
public class MainFrame
extends javax.swing.JFrame {
 …

 public static void main(String[] args)
{
   new MainFrame().setVisible(true);
 }
}

儘管這種錯誤出現在開始,但仍然違反了不應在EDT外的其他執行緒同Swing元件互動的原則。這個錯誤尤其容易犯,執行緒同步問題雖然不是馬上顯示出來,但是還要注意避免這樣書寫。

正確啟動UI介面應該如下:

public class MainFrame extends javax.swing.JFrame
{
 …

 public static void main(String[] args)
{
   SwingUtilities.invokeLater(new Runnable()
{
     public void run()
{
       new
MainFrame().setVisible(true);
     }
   });
 }
}

使用NetBeans IDE的開發者應該對這段程式碼很熟悉,NetBeans通常會自動生成這段程式碼。這段啟動程式碼雖然和SwingWorker沒有直接關係,但是這個程式設計正規化很重要。SwingUtilities類包含一些靜態方法幫你同UI元件互動,其中invokeLater方法意思是在EDT上執行其Runnable任務。Runnable介面定義了可作為獨立執行緒執行的任務。

在初始化執行緒中使用invokeLater方法能正確的初始化程式介面。就像前面文章所提到的,此方法是非同步執行的,也就是說呼叫會立即返回。建立介面後,大部分初始化執行緒基本上就結束了。

通常有兩種辦法呼叫此方法:
* SwingUtilities.invokeLater
* EventQueue.invokeLater
兩個方法都是正確的,java培訓選擇任何一個都可以。實際上,SwingUtilities版只是一個薄薄的封裝方法,它直接轉而呼叫EventQueue.invokeLater。因為Swing框架本身經常呼叫SwingUtilities,使用SwingUtilities可以減少程式引入的類。

另種將任務放到EDT執行的方法是SwingUtilities.invokeAndWait,不像invokeLater,invokeAndWait方法是阻塞執行的,它在EDT上執行Runnnable任務,直到任務執行完了,該方法才返回呼叫執行緒。

invokeLater和invokeAndWait都在事件派發佇列中的所有事件都處理完之後才執行它們的Runnable任務,也就是說,這兩個方法將Runnable任務放在事件佇列的末尾。

注意:雖然可以在其他執行緒上呼叫invokeLater,也可以在EDT上呼叫invokeLater,但是千萬不要在EDT執行緒上呼叫invokeAndWait方法!很容易理解,這樣做會造成執行緒競爭,程式就會陷入死鎖。

三 進一步理解事件派發執行緒(EDT)

當執行一個 Swing 程式時,會自動建立三個執行緒。
1.主執行緒,負責執行main 方法。
2. toolkit 執行緒,負責捕捉系統事件比如鍵盤、滑鼠移動等,程式設計師不會有任何程式碼在這個執行緒上執行。Toolkit執行緒的作用是把自己捕獲的事件傳遞給第三個執行緒,也就是事件派發執行緒。
3. 事件派發執行緒(EDT,Event Dispatcher Thread),顧名思義是用來派發事件(根據事件找到對應的事件處理程式碼)的執行緒。EDT接收來自 toolkit 執行緒的事件,並且將這些事件組織成一個佇列,EDT的工作內容就是將這個佇列中的事件按照順序派發給相應的事件監聽器,並且呼叫事件監聽器中的回撥函式,這也意味著,所有的事件處理程式碼都是在EDT而不是主執行緒中執行。
上面說到EDT中維護了一個事件的佇列,並且它們是按照順序派發的。由於事件派發是單執行緒的操作,所以只有等待前面事件監聽器的回撥函式執行完畢,才能夠執行元件更新的操作,以及繼續派發後面的事件。這樣導致的一個後果就是:當在一個事件監聽回撥函式中做了耗時的操作,那麼,介面會因此停住,並且介面上所有控制元件失效(不可觸發)。
解決這個問題的方法是:在事件處理函式中將耗時的操作放到新執行緒(一般稱之為工作執行緒)中執行,而不是讓其在EDT中執行。

案例:

一個視窗,有一個按鈕和一個label。點選按鈕,系統將做模仿匯入資料的動作,匯入資料之前需要檢測資料的合法性。並且,檢測資料和匯入資料這兩個步驟都需要耗費一定的時間。
如果沒有之前說到的EDT的概念,那麼你可能會這麼做:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 importBtn.addActionListener(newActionListener() { @Override publicvoid actionPerformed(ActionEvent e) { try{ lb.setText("1.檢查資料合法性..."); Thread.sleep(3000);//模仿檢測資料合法性 lb.setText("2.正在匯入資料..."); Thread.sleep(4000);//模仿匯入資料 lb.setText("3.匯入成功!"); }catch (InterruptedException e1) { e1.printStackTrace(); } } });

但是,如果執行一下的話,會發現現象是這樣:點選按鈕,介面卡住,按鈕變得不可觸發,直到一段時間(7秒)之後介面顯示“3.匯入成功”。期間並沒有顯示“1.檢查資料合法性”和“2.正在匯入資料”。
這個現象印證了上面說的理論:當事件派發執行緒中正在執行的事件監聽函式執行完畢,才能進行UI元件的重新整理操作,並且派發事件佇列中的下一個。

四 使用SwingUtilities.invokeLater實現的一個進度條例項

執行後截圖如下:

wKioL1Zw2ZbR7kqPAAA-wU5QcBw100.png

完整程式碼:

1 2 3 4 5 6 7 8 9 10 11 12

相關推薦

Java事件分發執行

一 Swing線程基礎 一個Swing程式中一般有下面三種類型的執行緒:     * 初始化執行緒(Initial Thread)     * UI事件排程執行緒(EDT)     * 任務執行緒(Worker Thread) 每個程式必須有一個main

Java執行之"事件分發執行"----Event Dispatch Thread

當執行GUI小程式(Applet)或應用程式(Application)時,main()方法中的程式碼會建立一個GUI並設定事件控制代碼.當呼叫Frame,Dialog,Window的setVisible(true)或瀏覽器顯示Applet時,我們就是在和GUI互動.   問題

Java Swing GUI 事件分發執行

一、事件分發執行緒和主執行緒            預設情況下,所有的AWT或者基於Swing的應用程式,都是開始於兩個執行緒的。其中一個就是主執行緒,它處理main方法裡面的程式碼。另外一個執行緒,被稱作“事件分發執行緒”(Event-dispatching thread

Java的多執行你只要看這一篇就夠了(轉)

引 如果對什麼是執行緒、什麼是程序仍存有疑惑,請先Google之,因為這兩個概念不在本文的範圍之內。 用多執行緒只有一個目的,那就是更好的利用cpu的資源,因為所有的多執行緒程式碼都可以用單執行緒來實現。說這個話其實只有一半對,因為反應“多角色”的程式程式碼,最起碼每個角色要給他一個執行緒吧,否

java常見的執行池(不看後悔,一看必懂)

Executor介面表示執行緒池,它的execute(Runnable task)方法用來執行Runnable型別的任務,ExecutorService是Executor的子介面,聲明瞭管理執行緒池的一些方法 Java.util.concurrent.Executors類包含了一些靜態

#圖文詳解:從實際和理論出發,帶你瞭解Java的多執行

這裡並沒有講什麼新東西,只是把多執行緒一些知識來個總結。大家懂得可以複習複習,還有些童鞋對多執行緒朦朧的可以拿這個做為入門~ 舉個栗子說明啥是多執行緒:玩遊戲,前面一堆怪,每個怪都是一個執行緒,你射了一槍,子彈飛出去了,這顆子彈也是一個執行緒。你開啟你的程序管理,看到你遊戲的後臺程序,這就是程序

java的多執行 // 基礎

java 中的多執行緒 簡介   程序 : 指正在執行的程式,並具有一定的獨立能力,即 當硬碟中的程式進入到記憶體中執行時,就變成了一個程序   執行緒 : 是程序中的一個執行單元,負責當前程式的執行。執行緒就是CPU通向程式的路徑        一個程序中只有一個執行緒,單執行緒程式  

java的守護執行

執行緒分類 守護執行緒(即daemon thread),是個服務執行緒,準確地來說就是服務其他的執行緒,這是它的作用——而其他的執行緒只有一種,那就是使用者執行緒。所以java裡執行緒分2種: 使用者執行緒:比如垃圾回收執行緒,就是最典型的守護執行緒 守護執行緒:就是應用程式裡的自定義執行緒

java學習(十) —— java的多執行概述

程序概述 程序:正在執行的程式,是系統進行資源分配和呼叫的獨立單位。 程序就是一個程式在一個數據集上的一次動態執行過程。 程序一般由程式、資料集、程序控制塊三部分組成。 每一個程序都有它自己的記憶體空間和系統資源。 我們編寫的程式用來描述程序要完成哪些功能以及如何

Java的多執行執行間通訊)

/學習筆記/ 執行緒間通訊: 多個執行緒在處理同一資源,但是任務卻不同。 先看一個例子,採用兩個執行緒執行進行輸入和輸出任務: //資源 class Resource { String name; String sex;

Java的多執行程式設計---面試

什麼是多執行緒 關鍵考點: a) 執行緒的概念。 b) 多執行緒的概念。 c) 多執行緒併發的含義。 答案: 執行緒是程序中的一個執行單元,又稱為輕量級程序,它和程序一樣擁有獨立的執行控制,由作業系統負責排程。 而多執行緒是這樣的一種機制:它允許在程式中併發

java程序和執行以及執行的狀態和方法

程序是cpu資源分配的最小單位,執行緒是cpu排程的最小單位。 一個程式至少有一個程序,一個程序至少有一個執行緒.  執行緒的劃分尺度小於程序,使得多執行緒程式的併發性高。 另外,程序在執行過程中擁有獨立的記憶體單元,而多個執行緒共享記憶體,從而極大地提高了程式的執行效率。

Java的多執行分析

一、 引言 1、程序 通俗的來說,程序就是我們開啟電腦後使用的一個個的應用程式。比如:開啟QQ會啟動一個程序,開啟瀏覽器又會啟動另一個程序。程序和我們的程式一一對應。關於程序特點,如下: (1)、 每個程序對應一定的記憶體地址空間,並且只能使用它自己的記憶體空間,各個程序間互

Java的多執行(2)

概述: 上一篇文章簡單的介紹了什麼是執行緒,以及執行緒的生命週期,還有建立執行緒的三種方式。接著本篇文章將總結有關執行緒同步的相關知識,主要講解使用synchronized實現執行緒同步。然後總結Java中鎖機制,明確什麼是物件鎖,什麼是類鎖。然後下篇文章講解關於Lock的

Java的多執行

在Java中要想實現多執行緒,有兩種方法: 繼承Thread類,重寫裡面的run()方法 實現Runable介面,重寫裡面的run()方法 那麼,到底使用哪一個方法會更好呢? 其實Thread類呼叫的run()方法就是Runable()的run()方法; 選

Java的多執行你只要看這一篇就夠了

/** * 生產者生產出來的產品交給店員 */ public synchronized void produce() { if(this.product >= MAX_PRODUCT) { try {

JAVA五種執行狀態的分析

Thred執行緒狀態的分析 Java執行緒的生命週期中,存在幾種狀態。 新建狀態: NEW: 執行緒建立之後,但是還沒有啟動(not yet started)。這時候它的狀態就是NEW 執行狀態: RUNNABLE: 正在Java虛擬機器下跑任務的執行緒的狀態。在RUNNABLE狀態下的

Java 的多執行你只要看這一篇就夠了

如果對什麼是執行緒、什麼是程序仍存有疑惑,請先Google之,因為這兩個概念不在本文的範圍之內。 用多執行緒只有一個目的,那就是更好的利用cpu的資源,因為所有的多執行緒程式碼都可以用單執行緒來實現。說這個話其實只有一半對,因為反應“多角色”的程式程式碼,最起碼每個角色要給他一個

初識Java的四大執行池和ThreadPoolExecutor的使用(歡迎指正)

初識Java中的四大執行緒池和ThreadPoolExecutor的使用(轉載+自身心得) 為什麼用執行緒池? 1.建立/銷燬執行緒伴隨著系統開銷,過於頻繁的建立/銷燬執行緒,會很大程度上影響處-理效率; 2.執行緒併發數量過多,搶佔系統資源從而導致阻塞; 3.對執行緒進行一些簡單的

java的多執行 內部類實現多執行 Runable介面的實現

  /* java.lang.Thead      java中的多執行緒    類從  Thread  覆蓋run方法    呼叫start啟動x執行緒  java中如果執行緒只剩後臺執行緒那麼程式終止執行 setDaemon設定為後臺執行緒     當進城中只剩下後臺