---------------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:
packagecom.siwuxie095.swingthread;
importjavax.swing.JFrame;
/**
*错误,不可以在主线程中创建UI元素或更改UI属性
*
* @author siwux
*
*/
public classBadDemo {
public staticvoidmain(String[] args) {
JFrame frame=newJFrame();
frame.setTitle("这是一个窗口");
frame.setSize(500,200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
GoodDemo.java:
packagecom.siwuxie095.swingthread;
importjavax.swing.JFrame;
importjavax.swing.SwingUtilities;
/**
*虽然效果相同,但窗体的创建和其属性的设定都变成了线程安全的操作
*
* SwingUtilities.invokeLater()的底层实际上就是EventQueue.invokeLater()
*
* EventQueue即事件派发线程,即UI线程
*
* @author siwux
*
*/
public classGoodDemo {
public staticvoidmain(String[] args) {
//在主方法中如果要创建一个新的窗体元素,可以通过静态方法
//调用SwingUtilities类的invokeLater()方法,传入匿名对象new Runnable()
SwingUtilities.invokeLater(newRunnable() {
@Override
publicvoidrun() {
JFrame frame=newJFrame();
frame.setTitle("这是一个窗口");
frame.setSize(500,200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
NewFrame.java:
packagecom.siwuxie095.swingthread;
importjava.awt.BorderLayout;
importjava.awt.EventQueue;
importjavax.swing.JFrame;
importjavax.swing.JPanel;
importjavax.swing.border.EmptyBorder;
//NewFrame直接继承自JFrame
public classNewFrame extendsJFrame {
privateJPanel contentPane;
/**
* Launch the application.
*
* EventQueue.invokeLater()是窗体创建是自带的方法
*/
public staticvoidmain(String[] args) {
EventQueue.invokeLater(newRunnable() {
publicvoidrun() {
try{
NewFrame frame = newNewFrame();
frame.setVisible(true);
} catch(Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
publicNewFrame() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = newJPanel();
contentPane.setBorder(newEmptyBorder(5, 5, 5, 5));
contentPane.setLayout(newBorderLayout(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】