已有101人关注
敢问高手,swing线程中,invokelater(runnable)是怎样调用run()方法的? 困扰我几天了,nnd
发表在Java图书答疑 2014-12-24
是否精华
版块置顶:
就是下面这个程序,我不知道它的执行顺序,只知道首先main();可是main后面跟了个run()方法,后面一个代码块里又有一个run()方法,到底调用哪个呢?整个程序的执行顺序是怎样?

package com.lzw;
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.InvocationTargetException;
import java.util.Vector;
import javax.swing.*;

public class EventQueueInvokerLaterDemo extends JFrame {
private ButtonGroup buttonGroup = new ButtonGroup(); // 按钮组
private JList list; // 列表组件
private Vector listData = new Vector(); // 列表数据

public static void main(String args[]) {
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
try {
EventQueueInvokerLaterDemo frame = new EventQueueInvokerLaterDemo();
} catch (Exception e) {
e.printStackTrace();
}
}
});
} catch (InterruptedException e) { // 捕获异常
e.printStackTrace();
} catch (InvocationTargetException e) { // 捕获异常
e.printStackTrace();
}
}

/**
 * Create the frame
 */
public EventQueueInvokerLaterDemo() {
super();
setBounds(100, 100, 236, 204); // 设置窗体大小位置
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final JScrollPane scrollPane = new JScrollPane(); // 创建高度面板
getContentPane().add(scrollPane, BorderLayout.CENTER);
list = new JList(); // 创建列表组件
scrollPane.setViewportView(list); // 滚动面板控制列表
final JPanel buttonPanel = new JPanel(); // 创建按钮面板
getContentPane().add(buttonPanel, BorderLayout.SOUTH);
final JButton button = new JButton(); // 创建按钮
button.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
do_button_actionPerformed(e); // 调用按钮事件处理方法
}
});
button.setText("添加列表选项"); // 设置按钮名称
buttonPanel.add(button); // 添加按钮到面板
final JPanel panel = new JPanel(); // 创建单选按钮面板
panel.setLayout(new GridLayout(0, 1)); // 使用网格布局
getContentPane().add(panel, BorderLayout.EAST);
final JRadioButton radioButton_1 = new JRadioButton(); // 创建单选按钮1
buttonGroup.add(radioButton_1);
radioButton_1.setText("单选1");
radioButton_1.setSelected(true);
panel.add(radioButton_1);
final JRadioButton radioButton_2 = new JRadioButton(); // 创建单选按钮2
buttonGroup.add(radioButton_2);
radioButton_2.setText("单选2");
panel.add(radioButton_2);
final JRadioButton radioButton_3 = new JRadioButton(); // 创建单选按钮3
buttonGroup.add(radioButton_3);
radioButton_3.setText("单选3");
panel.add(radioButton_3);
final JRadioButton radioButton_4 = new JRadioButton(); // 创建单选按钮4
buttonGroup.add(radioButton_4);
radioButton_4.setText("单选4");
panel.add(radioButton_4);
setVisible(true); // 显示窗体
}

/**
 * 这是<b>添加列表选项</b>按钮的事件处理方法
 * @param e 事件对象
 */
protected void do_button_actionPerformed(final ActionEvent e) {
new Thread() { // 开辟一个新的线程执行费时业务
public void run() {
for (int i = 0; i < 10; i++) { // 循环添加10个列表选项
Runnable runnable = new Runnable() { // 创建Runnable对象
public void run() { // 在run方法中操作Swing界面
listData.add("选项" + listData.size());
list.setListData(listData);
}
};
EventQueue.invokeLater(runnable); // 在事件队列中执行Runnable对象
try {
Thread.sleep(1000);  // 阻塞UI线程1秒
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}.start(); // 启动业务线程
}
}
分享到:
精彩评论 2
菜鸟级精英
学分:0 LV1
TA的每日心情
开心
2020-03-23 21:05:48
2014-12-24
沙发
理解这段代码之前,我们先理解一下EventQueue,在API中是这样描述的:
“EventQueue 是一个与平台无关的类,它将来自于底层同位体类和受信任的应用程序类的事件列入队列。 
它封装了异步事件指派机制,该机制从队列中提取事件,然后通过对此 EventQueue 调用 dispatchEvent(AWTEvent) 方法来指派这

些事件(事件作为参数被指派)。该机制的特殊行为是与实现有关的。指派实际排入到该队列中的事件(注意,正在发送到 

EventQueue 中的事件可以被合并)的唯一要求是: 
按顺序指派。 
也就是说,不允许同时从该队列中指派多个事件。 
指派顺序与它们排队的顺序相同。 
也就是说,如果 AWTEvent A 比 AWTEvent B 先排入到 EventQueue 中,那么事件 B 不能在事件 A 之前被指派。 ”

简单的理解EventQueue就是一个事件队列中执行器。
java的GUI都是的单线程,使用事件调度去执行线程可以增强代码的健壮性。否则,一个线程出现死锁,整个父类窗口也会彻底锁死



从你发的代码里可以看到,main方法中EventQueue.invokeAndWait() 方法参数是一个匿名内部线程类,这个线程只做了一件事,就

是主类实例化。这样写有两个好处:1、使用匿名线程,线程结束就会被回收,内存就会释放;2.将主类实例化放入invokeAndWait(

)等待指派,如果在此之前还有其他事件未处理,这个线程就会处于阻塞状态,而不是直接运行,防止多并发对造成系统不良影响

。其实EventQueue.invokeAndWait()完全可以去掉,直接实例化主类,不会对本程序产生任何影响。

后面的代码中,按钮的监听触发了一个do_button_actionPerformed()方法。方法开始又创建了一个匿名内部线程类,这么写的意

思就讲这个方法里所有的业务都交给一个新线程单独执行。线程开始后,创建了10个Runnable线程,每隔1秒钟并将一个线程交给了

EventQueue.invokeLater()进行指派,让EventQueue来分配这些线程的运作。

代码中所有的线程运行顺序就是
EventQueue.invokeAndWait() →do_button_actionPerformed()→Runnable×10......

当一个你想要放在主线程里要做的事情,但不用立刻去做,或者不想中止当前事务,调用EventQueue.invokeLater(runner);把该事

物放在事件队列最后,让主线程自行执行。使用InvokeLater不知道在什么时候会执行该事务,但好处是不会和其它事务起冲突。这个程序很小,完全看不出EventQueue的作用,将来编写复杂的大型frame程序时,就能用到EventQueue了。
吹雪_mrkj
学分:0 LV1
TA的每日心情
无聊
2020-03-24 10:21:38
2015-01-02
板凳
恩恩,谢谢了
首页上一页 1 下一页尾页 2 条记录 1/1页
手机同步功能介绍
友情提示:以下图书配套资源能够实现手机同步功能
明日微信公众号
明日之星 明日之星编程特训营
客服热线(每日9:00-17:00)
400 675 1066
mingrisoft@mingrisoft.com
吉林省明日科技有限公司Copyright ©2007-2022,mingrisoft.com, All Rights Reserved长春市北湖科技开发区盛北大街3333号长春北湖科技园项目一期A10号楼四、五层
吉ICP备10002740号-2吉公网安备22010202000132经营性网站备案信息 营业执照