主线程与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】

原文地址:https://www.cnblogs.com/siwuxie095/p/6672509.html