---------------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】