invokeLater和invokeAndWait
本人最近想写一个仿QQ,初学Swing对线程机制不太了解,所以在网上搜集了一些资料,结合自己的一些代码和想法,现将Swing线程机制以及invokeLater和invokeAndWait的学习所得分享给大家,文中不免有借鉴别人的“名言”,还请谅解。
Swing线程机制
首先swing是单线程的,这个是这篇文章的前提,也是意义所在,当swing界面程序启动的时候,会启动3个进程,1、主线程2、系统工具包线程:负责捕获操作系统事件,然后将事件转换成swing的事件,然后发送到事件派发线程EDT3、事件派发线程(EDT):将事件派发到各个组件,并负责调用绘制方法更新界面所有的事件,例如键盘,鼠标事件,都会由工具包线程转换成swing事件,然后放到事件队列EventQueue中,而这个EventQueue的派发机制是由EDT来管理的。
所以任何修改组件状态的方法都应该在EDT中执行,包括构造方法。Swing这样的构造原理经常会造成的情况就是,在EDT中执行长时间的事件,使EDT不能及时响应更新界面的事件,就是所说的界面卡住,这种不光是新手就是比较熟练的程序员也会犯的一个错误。所以必须避免在EDT中执行长时间的操作,而避免的方法就是多线程,启动另外的线程来处理冗长的操作,比如操作数据库,读写文件等,在这过程中可能要更新界面来给用户以提示,比如显示一个进度条,过一段事件更新一下界面,但是在EDT以外的线程中更新界面都是无效的,这在前面已经说过,要更新界面就要将对界面的更新操作放到EDT中,但是事件又是在另外的线程中执行的,要解决这个问题就要使用SwingUtilities提供的一个方法了invokeLater,
- public void actionPerformed(ActionEvent e){
- new Thread(new Runnable(){
- //do something
- SwingUtilities.invokeLater(new Runnable(){
- pulic void run(){
- //update the GUI
- }
- });
- }).start;
- }
这个方法的作用就是将一个更新界面的任务放到EDT中,EDT会在适当的时候进行调用以更新界面。invokeLater负责创建一个含有Runnable的特定事件,并让其在EDT中排队等待调用,当被调用时就会运行Runnable中的run方法进行派发。
invokeLater和invokeAndWait的区别
与invoikeLater一样,invokeAndWait也把可运行对象排入事件派发线程的队列中,invokeLater在把可运行的对象放入队列后就返回,而invokeAndWait一直等待知道已启动了可运行的run方法才返回。如果一个操作在另外一个操作执行之前必须从一个组件获得信息,则invokeAndWait方法是很有用的。
一般我们用到invokeLater,都是为了执行事件派发线程中的代码,将一段更新UI事件的代码派发到EventQueue中,但是我们可以从事件派发线程中调用invokeLater,却不能从事件派发线程中调用invokeAndWait,下面我们用代码来例证它们的不同:
SwingConsole.java文件:
- package swing.utilities;
- import javax.swing.*;
- public class SwingConsole {
- public static void run(final JFrame f, final int width, final int height){
- SwingUtilities.invokeLater(new Runnable(){
- public void run(){
- f.setTitle(f.getClass().getSimpleName());
- f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- f.setSize(width, height);
- f.setVisible(true);
- }
- });
- }
- }
TestAction.java文件:
- import java.awt.BorderLayout;
- import java.awt.FlowLayout;
- import java.awt.event.ActionEvent;
- import java.awt.event.ActionListener;
- import javax.swing.*;
- import swing.utilities.SwingConsole;
- public class TestAction extends JFrame {
- private static final long serialVersionUID = -7462155330900531124L;
- private JButton jb1 = new JButton("确定");
- private JTextField txt = new JTextField(10);
- public TestAction() {
- jb1.addActionListener(new ActionListener() {
- public void actionPerformed(ActionEvent e) {
- String name = ((JButton) e.getSource()).getText();
- txt.setText(name);
- }
- });
- setLayout(null);
- add(txt);
- add(jb1);
- txt.setBounds(50, 100, 200, 30);
- jb1.setBounds(270, 100, 70, 30);
- }
- public static void main(String[] args) {
- SwingUtilities.invokeLater(new Runnable() {
- public void run() {
- SwingConsole.run(new TestAction(), 500, 500);
- }
- });
- }
- }
我们在启动main线程的时候就把整个SwingConsole派发到EventQueue中,而本身SwingConsole已经处在EventQueue中,我们调用invokeLater没问题,运行正常!
再看我们修改之后的:
SwingConsole.java文件:
- package swing.utilities;
- import java.lang.reflect.InvocationTargetException;
- import javax.swing.*;
- public class SwingConsole {
- public static void run(final JFrame f, final int width, final int height){
- try {
- SwingUtilities.invokeAndWait(new Runnable(){
- public void run(){
- f.setTitle(f.getClass().getSimpleName());
- f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- f.setSize(width, height);
- f.setVisible(true);
- }
- });
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- } catch (InvocationTargetException e) {
- throw new RuntimeException(e);
- }
- }
- }
TestAction.java文件:
与前面一样
运行结果,出现异常:Exception in thread "AWT-EventQueue-0" java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread
在这里,我们把SwingConsole中的invokeLater改成了invokeAndWait,而之前SwingConsole已经处在EventQueue中了。
所以我们可以总结出它们的不同:可以从事件派发线程中调用invokeLater,却不能从事件派发线程中调用invokeAndWait,从事件派发线程调用invokeAndWait的问题是:invokeAndWait锁定调用它的线程,直到可运行对象从事件派发线程中派发出去并且该可运行的对象的run方法激活,如果从事件派发线程调用invoikeAndWait,则会发生死锁的状况,因为invokeAndWait正在等待事件派发,但是,由于是从事件派发线程中调用invokeAndWait,所以直到invokeAndWait返回后事件才能派发。
在这里我们还可以看到,在main函数里,我们在一开始就把整个操作都置于EventQueue中,这样虽然安全,但是不适合新手,因为新手很容易犯刚才那样的错误,一不小心就用了invokeAndWait而产生死锁。对于swing中的线程,我也还没有找到理想的处理机制,所以暂时就先到此,以后有经验才跟大家分享吧。
invokeLater和invokeAndWait相关推荐
- java invokelater 以及invokeandwait
SwingUtilities中invokeLater和invokeAndWait介绍 在Java中Swing是线程不安全的,是单线程的设计,这样的造成结果就是:只能从事件派发线程访问将要在屏幕上 ...
- IBM Java多线程 - 6.其它线程 API 详细信息
其它线程 API 详细信息 1. wait().notify() 和 notifyAll() 方法 2. 线程优先级 3. 线程组 4. SwingUtilities wait().notify() ...
- 编写多线程Java应用程序常见问题
几乎所有使用 AWT 或 Swing 编写的画图程序都需要多线程.但多线程程序会造成许多困难,刚开始编程的开发者常常会发现他们被一些问题所折磨,例如不正确的程序行为或死锁. 在本文中,我们将探讨使用多 ...
- Java 数据库进度条_java进度条
练习JProgressBar结合Timer使用. 代码如下: package luojing; import java.awt.*; import java.awt.event.*; import j ...
- Swing中的并发-使用SwingWorker线程模式
Swing中的并发-使用SwingWorker线程模式 原创作品http://zhangjunhd.blog.51cto.com/113473/34727 Blog: [url]http://zhan ...
- Java线程—如何解决Swing的单线程问题-----------Swing线程机制
首先swing是单线程的,这个是这篇文章的前提,也是意义所在,当swing界面程序启动的时候,会启动3个进程, 1.主线程 2.系统工具包线程:负责捕获操作系统事件,然后将事件转换成swing的事件, ...
- 《FilthyRichClients》读书笔记(一)-SwingのEDT
<FilthyRichClients>读完了前几个章节,现将我的体会结合工作以来从事Swing桌面开发的经验,对本书的一些重要概念进行一次 分析,对书中的一些遗漏与模糊的地方及时补充,同时 ...
- java怎么做界面设计_11-Java 界面设计
(一)Java界面设计概述 1.Java 界面设计的用途 2.AWT 简介 (1)Abstract Windows Toolkit 是最原始的工具包. 3.Swing 简介 4.SWT 简介 5.如何 ...
- java edt,java并发之EDT测试
测试代码如下: 1.耗时计算没有单独起线程处理,耗时计算在EDT线程执行,导致界面没有响应,处于卡死状态 package thread; import java.awt.event.ActionEve ...
最新文章
- 【算法笔记】哈密顿问题
- IntelliJ IDEA 、 Android Stadio 不显示Version Contro窗口
- 小师妹学JavaIO之:NIO中Channel的妙用
- 魔兽世界工程学技能1-375冲级攻略
- 四大开源项目联合发布 腾讯已成Github全球贡献前十公司!
- 不要等到离职,才明白这些道理
- java使用properties_Java中使用Properties配置文件的简单方法
- python4k高清图片_第一次接触,尝试用python抓取国外4k高清图像数据,真方便
- 李宏毅机器学习笔记——深度学习
- 麦克风声源定位原理_关于基于麦克风阵列的声源被动定位系统的设计
- 织梦Dedecms忘记管理员后台密码解决办法
- QoS服务质量二令牌桶算法及QoS业务分类
- 怎么将webm文件转换成MP4格式在手机上播放
- 计算机配置价格对比,硬件配置、价格对比
- 语法错误 : 缺少“;”(在“类型”的前面)的解决方案
- SOLID原理的详细信息。
- 手把手带你用viewpager实现gallary效果,外加无限循环,自动轮播
- Flask入门教程(视频教程笔记)
- 4篇高水平论文认定A类博士!享税后120万安家费!直接入编,三年副教授待遇...
- YUV数据格式的转换(NV12ToI420)和旋转(旋转90度)