本人最近想写一个仿QQ,初学Swing对线程机制不太了解,所以在网上搜集了一些资料,结合自己的一些代码和想法,现将Swing线程机制以及invokeLaterinvokeAndWait的学习所得分享给大家,文中不免有借鉴别人的“名言”,还请谅解。

Swing线程机制

首先swing是单线程的,这个是这篇文章的前提,也是意义所在,当swing界面程序启动的时候,会启动3个进程,1、主线程2、系统工具包线程:负责捕获操作系统事件,然后将事件转换成swing的事件,然后发送到事件派发线程EDT3、事件派发线程(EDT):将事件派发到各个组件,并负责调用绘制方法更新界面所有的事件,例如键盘,鼠标事件,都会由工具包线程转换成swing事件,然后放到事件队列EventQueue中,而这个EventQueue的派发机制是由EDT来管理的。

所以任何修改组件状态的方法都应该在EDT中执行,包括构造方法。Swing这样的构造原理经常会造成的情况就是,在EDT中执行长时间的事件,使EDT不能及时响应更新界面的事件,就是所说的界面卡住,这种不光是新手就是比较熟练的程序员也会犯的一个错误。所以必须避免在EDT中执行长时间的操作,而避免的方法就是多线程,启动另外的线程来处理冗长的操作,比如操作数据库,读写文件等,在这过程中可能要更新界面来给用户以提示,比如显示一个进度条,过一段事件更新一下界面,但是在EDT以外的线程中更新界面都是无效的,这在前面已经说过,要更新界面就要将对界面的更新操作放到EDT中,但是事件又是在另外的线程中执行的,要解决这个问题就要使用SwingUtilities提供的一个方法了invokeLater

Java代码 
  1. public void actionPerformed(ActionEvent e){
  2. new Thread(new Runnable(){
  3. //do something
  4. SwingUtilities.invokeLater(new Runnable(){
  5. pulic void run(){
  6. //update the GUI
  7. }
  8. });
  9. }).start;
  10. }

这个方法的作用就是将一个更新界面的任务放到EDT中,EDT会在适当的时候进行调用以更新界面。invokeLater负责创建一个含有Runnable的特定事件,并让其在EDT中排队等待调用,当被调用时就会运行Runnable中的run方法进行派发。

invokeLaterinvokeAndWait的区别

invoikeLater一样,invokeAndWait也把可运行对象排入事件派发线程的队列中,invokeLater在把可运行的对象放入队列后就返回,而invokeAndWait一直等待知道已启动了可运行的run方法才返回。如果一个操作在另外一个操作执行之前必须从一个组件获得信息,则invokeAndWait方法是很有用的。

一般我们用到invokeLater,都是为了执行事件派发线程中的代码,将一段更新UI事件的代码派发到EventQueue中,但是我们可以从事件派发线程中调用invokeLater,却不能从事件派发线程中调用invokeAndWait,下面我们用代码来例证它们的不同:

SwingConsole.java文件:

Java代码 
  1. package swing.utilities;
  2. import javax.swing.*;
  3. public class SwingConsole {
  4. public static void run(final JFrame f, final int width, final int height){
  5. SwingUtilities.invokeLater(new Runnable(){
  6. public void run(){
  7. f.setTitle(f.getClass().getSimpleName());
  8. f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  9. f.setSize(width, height);
  10. f.setVisible(true);
  11. }
  12. });
  13. }
  14. }

TestAction.java文件:

Java代码 
  1. import java.awt.BorderLayout;
  2. import java.awt.FlowLayout;
  3. import java.awt.event.ActionEvent;
  4. import java.awt.event.ActionListener;
  5. import javax.swing.*;
  6. import swing.utilities.SwingConsole;
  7. public class TestAction extends JFrame {
  8. private static final long serialVersionUID = -7462155330900531124L;
  9. private JButton jb1 = new JButton("确定");
  10. private JTextField txt = new JTextField(10);
  11. public TestAction() {
  12. jb1.addActionListener(new ActionListener() {
  13. public void actionPerformed(ActionEvent e) {
  14. String name = ((JButton) e.getSource()).getText();
  15. txt.setText(name);
  16. }
  17. });
  18. setLayout(null);
  19. add(txt);
  20. add(jb1);
  21. txt.setBounds(5010020030);
  22. jb1.setBounds(2701007030);
  23. }
  24. public static void main(String[] args) {
  25. SwingUtilities.invokeLater(new Runnable() {
  26. public void run() {
  27. SwingConsole.run(new TestAction(), 500500);
  28. }
  29. });
  30. }
  31. }

我们在启动main线程的时候就把整个SwingConsole派发到EventQueue中,而本身SwingConsole已经处在EventQueue中,我们调用invokeLater没问题,运行正常!

再看我们修改之后的:

SwingConsole.java文件:

Java代码 
  1. package swing.utilities;
  2. import java.lang.reflect.InvocationTargetException;
  3. import javax.swing.*;
  4. public class SwingConsole {
  5. public static void run(final JFrame f, final int width, final int height){
  6. try {
  7. SwingUtilities.invokeAndWait(new Runnable(){
  8. public void run(){
  9. f.setTitle(f.getClass().getSimpleName());
  10. f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  11. f.setSize(width, height);
  12. f.setVisible(true);
  13. }
  14. });
  15. catch (InterruptedException e) {
  16. throw new RuntimeException(e);
  17. catch (InvocationTargetException e) {
  18. throw new RuntimeException(e);
  19. }
  20. }
  21. }

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相关推荐

  1. java invokelater 以及invokeandwait

    SwingUtilities中invokeLater和invokeAndWait介绍    在Java中Swing是线程不安全的,是单线程的设计,这样的造成结果就是:只能从事件派发线程访问将要在屏幕上 ...

  2. IBM Java多线程 - 6.其它线程 API 详细信息

    其它线程 API 详细信息 1. wait().notify() 和 notifyAll() 方法 2. 线程优先级 3. 线程组 4. SwingUtilities wait().notify() ...

  3. 编写多线程Java应用程序常见问题

    几乎所有使用 AWT 或 Swing 编写的画图程序都需要多线程.但多线程程序会造成许多困难,刚开始编程的开发者常常会发现他们被一些问题所折磨,例如不正确的程序行为或死锁. 在本文中,我们将探讨使用多 ...

  4. Java 数据库进度条_java进度条

    练习JProgressBar结合Timer使用. 代码如下: package luojing; import java.awt.*; import java.awt.event.*; import j ...

  5. Swing中的并发-使用SwingWorker线程模式

    Swing中的并发-使用SwingWorker线程模式 原创作品http://zhangjunhd.blog.51cto.com/113473/34727 Blog: [url]http://zhan ...

  6. Java线程—如何解决Swing的单线程问题-----------Swing线程机制

    首先swing是单线程的,这个是这篇文章的前提,也是意义所在,当swing界面程序启动的时候,会启动3个进程, 1.主线程 2.系统工具包线程:负责捕获操作系统事件,然后将事件转换成swing的事件, ...

  7. 《FilthyRichClients》读书笔记(一)-SwingのEDT

    <FilthyRichClients>读完了前几个章节,现将我的体会结合工作以来从事Swing桌面开发的经验,对本书的一些重要概念进行一次 分析,对书中的一些遗漏与模糊的地方及时补充,同时 ...

  8. java怎么做界面设计_11-Java 界面设计

    (一)Java界面设计概述 1.Java 界面设计的用途 2.AWT 简介 (1)Abstract Windows Toolkit 是最原始的工具包. 3.Swing 简介 4.SWT 简介 5.如何 ...

  9. java edt,java并发之EDT测试

    测试代码如下: 1.耗时计算没有单独起线程处理,耗时计算在EDT线程执行,导致界面没有响应,处于卡死状态 package thread; import java.awt.event.ActionEve ...

最新文章

  1. 【算法笔记】哈密顿问题
  2. IntelliJ IDEA 、 Android Stadio 不显示Version Contro窗口
  3. 小师妹学JavaIO之:NIO中Channel的妙用
  4. 魔兽世界工程学技能1-375冲级攻略
  5. 四大开源项目联合发布 腾讯已成Github全球贡献前十公司!
  6. 不要等到离职,才明白这些道理
  7. java使用properties_Java中使用Properties配置文件的简单方法
  8. python4k高清图片_第一次接触,尝试用python抓取国外4k高清图像数据,真方便
  9. 李宏毅机器学习笔记——深度学习
  10. 麦克风声源定位原理_关于基于麦克风阵列的声源被动定位系统的设计
  11. 织梦Dedecms忘记管理员后台密码解决办法
  12. QoS服务质量二令牌桶算法及QoS业务分类
  13. 怎么将webm文件转换成MP4格式在手机上播放
  14. 计算机配置价格对比,硬件配置、价格对比
  15. 语法错误 : 缺少“;”(在“类型”的前面)的解决方案
  16. SOLID原理的详细信息。
  17. 手把手带你用viewpager实现gallary效果,外加无限循环,自动轮播
  18. Flask入门教程(视频教程笔记)
  19. 4篇高水平论文认定A类博士!享税后120万安家费!直接入编,三年副教授待遇...
  20. YUV数据格式的转换(NV12ToI420)和旋转(旋转90度)

热门文章

  1. 解决B站视频声音小的情况
  2. Windows7服务优化教程
  3. JS 如何动态获取本地文件夹中的所有图片
  4. 无用的“数据”?有用的“大数据”
  5. mvc控制器返回操作结果封装
  6. html5文字环绕图片,css怎么让文字环绕图片?
  7. idea 生成 Serializable 序列化 UID 的快捷键
  8. react native scrollView FlatList 多级联动
  9. layui 下拉列表框获取值
  10. 叉乘点乘混合运算公式_初学者的Excel公式及其引用方法指南