![](/img/trans.png)
[英]create new thread inside actionPerformed and Event Dispatch Thread (EDT) issue
[英]Is there a way to set up two or more the event dispatch thread (EDT)?
Java 是否能够一次创建多个 EDT?
我正在尝试设置 EDT,以及它如何更新“重型”面板的内容,其中可能嵌入了十几个面板,总共有数百个组件。 目前我有
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
panel.update();
}
});
}
我看过以下帖子:
http://en.wiki2.org/wiki/Event_dispatching_thread
等等。
我有点理解,如果有一个 EDT 必须处理的十几个事件,Java 已经有一个内部调度机制来对这些事件进行分组/优先级排序。
根据http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html
"This is necessary because most Swing object methods are not "thread safe": invoking them from multiple threads risks thread interference or memory consistency errors."
那么,如果我在下面创建一个带有 new Thread(new Runnable() {... }.start() 的第二个 EDT 怎么办?
java 会因为担心线程安全而自动将两个 EDT 合并回一个吗?
new Thread(new Runnable() {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
panel.update();
}
});
}
}).start();
只能有一个Event Dispatch Thread!
但是为什么你甚至想要有多个线程? 即使对于具有许多组件的“重型”面板(在我目前正在进行的应用中,必须有1000个组件),一个EDT就足够了。 请记住,您不应该在EDT上执行任何占用大量CPU时间的任务。 否则,您将阻止EDT更新事件,并且您的GUI将在响应用户输入时变得“迟缓”。
还要记住,所有GUI组件都应该仅在EDT中创建和操作,因为许多组件不是线程保存。 忽略此指南可能适用于特定任务,但迟早会出现奇怪的行为和/或崩溃!
Swing GUI是单线程的。 那个单线程是EDT。 如果你想引入第二个EDT(并且仍然有GUI工作),你还必须重写很多内部Swing代码,以解决线程安全性增加的复杂性。
添加另一个EDT会为性能的未知量增加(或减少)带来更多复杂性。
以下适用于使用 Sun 工具包的情况。 我不确定其他 Java 实现(尚未测试)。
如果工具包是从来自不同线程组的多个线程初始化的,则可以有多个 EDT 线程。
PoC 代码:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
public class Test {
public static void main(String[] argv) {
for (int i = 0; i < 5; i++) {
// the separate thread group is needed at least for the Sun toolkit
ThreadGroup tg = new ThreadGroup("Test Group " + i);
Thread t = new Thread(tg, new Runnable() {
@Override
public void run() {
startApp();
}
}, "Test " + i);
t.start();
}
}
private static void startApp() {
sun.awt.SunToolkit.createNewAppContext();
final JFrame frm = new JFrame(Thread.currentThread().getName()) {
@Override
public void setVisible(boolean b) {
super.setVisible(b);
System.out.println("Closed");
if (!b) dispose();
}
};
final JTextArea ta = new JTextArea();
frm.add(ta);
JButton btn = new JButton("Dialog");
// Showing a modal dialog will block only this frame
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frm, "Test message from " + frm.getTitle());
}
});
frm.add(btn, BorderLayout.SOUTH);
frm.setPreferredSize(new Dimension(300, 300));
frm.pack();
frm.show();
Thread t = new Thread(new Runnable() {
int i = 0;
@Override
public void run() {
try {
while (true) {
i++;
if (!frm.isVisible()) break;
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
try {
ta.getDocument().insertString(0, "Test " + i + " " +
Thread.currentThread().hashCode() + // This is to show that we are actually on a different thread as invokeAndWait is static and one may suspect a different behaviour
"\n", null);
} catch (Throwable t) {
t.printStackTrace();
}
}
});
Thread.sleep(1000 + (int)(Math.random() * 500));
}
Thread.sleep(4000); // This is just to show that the deamon thread might not have ended before the toolkit calls System.exit
} catch (Throwable t) {
t.printStackTrace();
}
System.out.println("Thread " + Thread.currentThread().getName() + " exit");
}
});
t.setDaemon(true);
t.start();
}
}
上面的代码演示了在单独的 EDT 上打开 5 帧。 当每个框架关闭并设置时,相应的 EDT 结束。 当所有框架都关闭并处理后,应用程序将退出(自动)。
笔记:
我使用上述方法来测量启用了换行的 JTextArea 的高度,该 JTextArea 填充了可能需要一些时间的大量不同文本,在此期间我不想阻塞主 UI。 结果(测量的高度)用于主 UI。
使用 Java 1.6.0_25 和 1.8.0_60 进行测试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.