主線程與UI線程簡介


---------------siwuxie095

   

   

   

   

   

   

   

Java 程序的主線程

   

當 Java 程序啟動時,一個線程立刻運行,該線程通常叫做程序的

主線程(main Thread),因為它是程序開始時就執行的

   

   

一般來說,某個類中會有一個 main 函數,當程序啟動時,

該函數就會第一個自動得到執行,並成為程序的主線程

   

   

主線程的特征如下:

   

· 主線程是產生其他子線程的線程

   

· 主線程中執行程序的控制

   

· 通常主線程必須最后完成執行,因為它執行各種關閉動作

   

   

『永遠不要在主線程中直接操作界面』

   

   

   

   

   

Swing 的 UI 線程

   

Swing API 的設計目標是強大、靈活和易用

   

Swing 組件不支持多線程訪問,程序要操作 或 更改界面內容,

必須向單一線程執行請求,把這個單一的線程稱為事件派發線程

(可簡稱為 UI 線程)

   

這意味着 Swing 是線程不安全的,所有對於 UI 元素的修改都必須

提交給 UI 線程執行,不能在主線程 或 其他任何線程中直接操作 UI

的內容

   

如果要從 UI 線程 或 繪制代碼以外的地方 訪問 UI,需要使用 SwingUtilities 類

invokeLater() 或 invokeAndWait() 方法

   

如果要處理一些耗費大量計算能力 I/O 能力限制的工作,可以使用一個

線程工具類,如:SwingWorker 或 Timer

   

   

   

   

   

如:

   

工程名:SwingThreadSafeTest

包名:com.siwuxie095.swingthread

類名:BadDemo.java、GoodDemo.java、NewFrame.java

   

   

工程結構目錄如下:

   

   

   

   

BadDemo.java:

   

package com.siwuxie095.swingthread;

   

import javax.swing.JFrame;

   

/**

* 錯誤,不可以在主線程中創建UI元素 更改UI屬性

*

* @author siwux

*

*/

   

public class BadDemo {

   

public static void main(String[] args) {

 

JFrame frame=new JFrame();

frame.setTitle("這是一個窗口");

frame.setSize(500,200);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setVisible(true);

}

   

}

   

   

   

GoodDemo.java:

   

package com.siwuxie095.swingthread;

   

import javax.swing.JFrame;

import javax.swing.SwingUtilities;

   

/**

* 雖然效果相同,但窗體的創建和其屬性的設定都變成了線程安全的操作

*

* SwingUtilities.invokeLater()的底層實際上就是EventQueue.invokeLater()

*

* EventQueue 即事件派發線程,即 UI 線程

*

* @author siwux

*

*/

   

public class GoodDemo {

 

public static void main(String[] args) {

 

//在主方法中如果要創建一個新的窗體元素,可以通過靜態方法

//調用 SwingUtilities類的 invokeLater() 方法,傳入匿名對象 new Runnable()

SwingUtilities.invokeLater(new Runnable() {

 

@Override

public void run() {

JFrame frame=new JFrame();

frame.setTitle("這是一個窗口");

frame.setSize(500,200);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setVisible(true);

}

});

}

   

}

   

   

   

NewFrame.java:

   

package com.siwuxie095.swingthread;

   

import java.awt.BorderLayout;

import java.awt.EventQueue;

   

import javax.swing.JFrame;

import javax.swing.JPanel;

import javax.swing.border.EmptyBorder;

   

//NewFrame 直接繼承自 JFrame

public class NewFrame extends JFrame {

   

private JPanel contentPane;

   

/**

* Launch the application.

*

* EventQueue.invokeLater() 是窗體創建是自帶的方法

*/

 

public static void main(String[] args) {

EventQueue.invokeLater(new Runnable() {

public void run() {

try {

NewFrame frame = new NewFrame();

frame.setVisible(true);

} catch (Exception e) {

e.printStackTrace();

}

}

});

}

   

/**

* Create the frame.

*/

public NewFrame() {

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

setBounds(100, 100, 450, 300);

contentPane = new JPanel();

contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));

contentPane.setLayout(new BorderLayout(0, 0));

setContentPane(contentPane);

}

   

}

   

   

   

對比 BadDemo.java 和 GoodDemo.java:

   

雖然效果一樣,但不能在主線程中直接創建 UI 元素 或 更改 UI 屬性,這是線程不安全的

   

而使用 SwingUtilities.invokeLater() 方法,在其中創建窗體和設定屬性就是線程安全的

   

   

   

對比 GoodDemo.java 和 NewFrame.java:

   

效果不談(次要),主要看其主方法中的實現,如下:

   

GoodDemo.java 使用 SwingUtilities.invokeLater() 方法

   

   

   

NewFrame.java 使用 EventQueue.invokeLater() 方法

   

   

   

SwingUtilities 屬於 javax.swing.SwingUtilities 類,

EventQueue 屬於 java.awt.EventQueue

   

二者作用完全相同

   

「EventQueue 即事件派發線程,也即 UI 線程」

   

   

   

實際上 SwingUtilities.invokeLater() 的底層就是 EventQueue.invokeLater()

   

   

   

   

   

一般情況下,如果將窗體創建為一個新的類對象(即類似於這里的 NewFrame.java),

想要在另外一個類中調用,而不在窗體程序中進行調用,可以將窗體程序中自動生成的

主方法代碼剪切過去

   

   

   

   

   

   

【made by siwuxie095】


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM