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