主线程与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元素 * * @author siwux * */ public class BadDemo { public static
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
//在主方法中如果要创建一个新的窗体元素,可以通过静态方法 //调用 SwingUtilities类的 invokeLater() 方法,传入匿名对象 new Runnable() SwingUtilities.invokeLater(new Runnable() {
@Override public 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 EventQueue.invokeLater(new Runnable() { public 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】
主线程与UI线程简介的更多相关文章
- C# 委托 / 跨线程访问UI / 线程间操作无效: 从不是创建控件“Form1”的线程访问它
C# 委托 / 跨线程访问UI / 线程间操作无效: 从不是创建控件“Form1”的线程访问它 网上的代码都比较复杂,还是这个简单 见代码, 简易解决办法: 主窗体代码 using System; ...
- 新建线程与UI线程间的通信
现在用一个实例来演示一下自己的新建线程与UI线程间的通信. UI界面包含3个控件: 一个输入框,用来输入数字: 一个显示框,用来显示从2开始,到输入数字之间的所有质数: 一个按钮,点击后获取输入框输入 ...
- [Android学习笔记]子线程更新UI线程方法之Handler
关于此笔记 不讨论: 1.不讨论Handler实现细节 2.不讨论android线程派发细节 讨论: 子线程如何简单的使用Handler更新UI 问题: android开发时,如何在子线程更新UI? ...
- OkHttp3几个简单的例子和在子线程更新UI线程的方法
okHttp用于android的http请求.据说很厉害,我们来一起尝尝鲜.但是使用okHttp也会有一些小坑,后面会讲到如何掉进坑里并爬出来. 首先需要了解一点,这里说的UI线程和主线程是一回事儿. ...
- Android ActivityThread(主线程或UI线程)简介
1. ActivityThread功能 它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),并根据AMS的要求(通过IApplicationThread接口,AMS为Client ...
- C#用副线程改主线程(UI线程)的控件属性的方法(包括Winform和WPF)
C#用副线程去试图修改主线程的UI控件会报出异常,解决方案是使用副线程注册事件通知主线程自己去修改UI控件 在winform中,方法如下 private void button1_Click(obje ...
- C#中后台线程和UI线程的交互
在C#中,从Main()方法开始一个默认的线程,一般称之为主线程,如果在这个进行一些非常耗CPU的计算,那么UI界面就会被挂起而处于假死状态,也就是说无法和用户进行交互了,特别是要用类似进度条来实时显 ...
- WPF线程获取UI线程
WPF中只能是UI线程才可以改变UI控件相关,当采用多线程工作时,可用以下代码获取 UI线程进行操作: App.Current.Dispatcher.Invoke((Action)delegate() ...
- C#在非UI线程调用UI线程的控件
首先需要定义一个委托(delegate): private delegate void delegateSetProcessBarVal(int value); 然后定义一个方法来执行具体的操作: p ...
随机推荐
- Data Structure Array: Longest Monotonically Increasing Subsequence Size
http://www.geeksforgeeks.org/longest-monotonically-increasing-subsequence-size-n-log-n/ #include < ...
- ios多种语言的本地化思路
多语言在应用程序中一般有两种做法: 一.程序中提供给用户自己选择的机会: 二.根据当前用户当前移动设备的语言自动将我们的app切换对应语言. 第一种做法比较简单完全靠自己的发挥了,这里主要讲第二种做法 ...
- python3 内置常用函数系列一
python3 内置了一系列的常用函数, python英文官方文档详细说明:点击查看, 为了方便查看,将内置常用的函数的记录一下来. Python3版本所有的内置函数: 1.abs() print(a ...
- 20145229吴姗珊《Java程序设计》2天总结
20145229吴姗珊<Java程序设计>2天总结 教材学习内容总结 异常处理 1.使用try.catch Java中所有错误都会被包装成对象,可以尝试(try)执行程序并捕捉(catch ...
- RabbitMQ事务确认机制(生产者)
消息确认机制 生产者 消费者 消费者如何确保消息一定消费成功 队列和消费者建立长连接,推送或者拉取形式. 消费者通过自动应答或者手动应答,队列服务器等待应答结果,如果没有应答结果那么保留给下一个消费者 ...
- java入门了解08
1.集合深入 (一)hashSet实现原理: 当我们添加一个元素,HashSet会计算出其Hash值,再根据hash值在哈希表中找出存储他的位置 有两种情况:a.如果算出的hash值在哈希表中位置没有 ...
- Tomcat处理HTTP请求源码分析(上)
Tomcat处理HTTP请求源码分析(上) 作者 张华 发布于 2011年12月8日 | 8 讨论 分享到: 微博 微信 Facebook Twitter 有道云笔记 邮件分享 稍后阅读 我的阅读清单 ...
- Codeforces 219D Choosing Capital for Treeland:Tree dp
题目链接:http://codeforces.com/problemset/problem/219/D 题意: 给你一棵树,n个节点. 树上的边都是有向边,并且不一定是从父亲指向儿子的. 你可以任意翻 ...
- 0X7FFFFFFF,0X80000000
给int类型赋值的话,0X7FFFFFFF代表最大值,0X80000000代表最小值 INT_MAX 代表最大值, INT_MIN 代表最小值 #include<iostream> #in ...
- 7_DoubleBuffer 游戏编程中的双缓存模式
### double buffer 双缓存 简单说: 当一个缓存被读取的时候,往另一个缓存里写入, 如此交替 #### the pattern 有两个缓存实例,一个是 current buffer, ...