在人们的帮助下,我能够获得以下简单的GUI倒数的工作代码(它仅显示一个倒数秒的窗口)。我的这段代码的主要问题是invokeLater
东西。
据我了解invokeLater
,它将任务发送到事件分发线程(EDT),然后EDT在“可以”时执行该任务(无论如何)。 那正确吗?
据我了解,代码的工作方式如下:
在main
方法中,我们invokeLater
用来显示窗口(showGUI
方法)。换句话说,显示窗口的代码将在EDT中执行。
在该main
方法中,我们还启动counter
,计数器(通过构造)在另一个线程中执行(因此不在事件调度线程中执行)。对?
该counter
是在一个单独的线程中执行,并定期调用updateGUI
。updateGUI
应该更新GUI。而且GUI正在EDT中工作。因此,updateGUI
也应在EDT中执行。这就是的代码updateGUI
包含在中的原因invokeLater
。那正确吗?
对我来说不清楚的是为什么我们counter
从EDT 致电。无论如何,它不会在EDT中执行。它立即启动,并在其中counter
执行新线程。那么,
为什么counter
在invokeLater
块之后不能在main方法中调用in 呢?
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class CountdownNew {
static JLabel label;
// Method which defines the appearance of the window.
public static void showGUI() {
JFrame frame = new JFrame("Simple Countdown");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
label = new JLabel("Some Text");
frame.add(label);
frame.pack();
frame.setVisible(true);
}
// Define a new thread in which the countdown is counting down.
public static Thread counter = new Thread() {
public void run() {
for (int i=10; i>0; i=i-1) {
updateGUI(i,label);
try {Thread.sleep(1000);} catch(InterruptedException e) {};
}
}
};
// A method which updates GUI (sets a new value of JLabel).
private static void updateGUI(final int i, final JLabel label) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
label.setText("You have " + i + " seconds.");
}
}
);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
showGUI();
counter.start();
}
});
}
}
如果我正确理解了您的问题,您会想知道为什么不能这样做:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
showGUI();
}
});
counter.start();
}
之所以无法执行此操作,是因为调度程序不做任何保证……仅因为您调用了showGUI()
之后又调用了counter.start()
它并不意味着in中的代码showGUI()
将在.run方法中的代码之前执行counter
。
这样想:
JLabel
。JLabel
to的存在,因此它可以调用label.setText("You have " + i + " seconds.");
现在您有一个竞争条件:
JLabel
必须在counter
线程启动之前创建,如果未在计数器线程启动之前创建它,那么您的计数器线程将setText
在未初始化的对象上进行调用。
为了保证比赛的条件被消除,我们必须保证执行和顺序 的一种方式
,以保证它是执行showGUI()
和counter.start()
在同一线程上按顺序:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
showGUI();
counter.start();
}
});
}
现在showGUI();
和counter.start();
从同一线程执行,因此JLabel
将在counter
开始之前创建。
更新:
问: 我不了解此线程有什么特别之处。
答:
Swing事件处理代码在称为事件调度线程的特殊线程上运行。大多数调用Swing方法的代码也都在此线程上运行。这是必需的,因为大多数Swing对象方法都不是“线程安全的”:从多个线程中调用它们可能会导致线程干扰或内存一致性错误。1个问: 因此,如果有GUI,为什么要在单独的线程中启动它?
答: 可能有比我更好的答案,但是,如果要从EDT更新GUI(您需要这样做),则必须从EDT启动它。问: 为什么我们不能像其他线程一样直接启动线程?
答: 请参阅先前的答案。问: 为什么我们使用一些invokeLater,以及为什么此线程(EDT)在就绪后开始执行请求。 为什么它并不总是准备就绪?
答: EDT可能还需要处理其他一些AWT事件。
invokeLater
使doRun.run()在AWT事件分配线程上异步执行。处理完所有待处理的AWT事件后,就会发生这种情况。当应用程序线程需要更新GUI时,应使用此方法。2
问题内容: 我了解了swing是不是线程安全的。深入研究,我发现必须对事件分发线程进行任何对swing组件的修改,以防止与多线程相关的各种问题。但是,这些信息似乎完全到此为止。似乎没有一个很好的教程可以解释如何在Internet上可以访问的任何地方进行此操作。 从与其他问题有关的已发布代码中收集信息,似乎我将不得不在程序中的每个单独的swing修改周围放置一个不整洁的代码块(例如本例中的代码):
问题内容: 1.考虑我的代码在我拥有的JPanel的某行上,我是否自动在EDT上运行? 2.对于不属于GUI,JPanels或其他视图类的其他所有类的相同问题,简单逻辑类。 3.如果我有正在播放音乐的JPanel,则音乐应该在事件分发线程或非EDT的其他线程上运行(因为没有阻塞GUI,尽管我感觉运行没有问题) (来自EDT)? 注意:我想要一个一般规则,而无需使用“ 谢谢” 问题答案: 没有。 没
所以我经常从朋友那里听到Node.js是如何使用单个线程来完成所有工作的。我认为这意味着它通过一个等待“accept”方法的循环线程接受新的套接字连接(像大多数web服务器一样),然后它不是将接收到的套接字委托给一个新线程来处理,而是以某种方式获得一个线程来处理所有的连接。 但每个人都告诉我情况并非如此,它实际上是事件驱动的--这样事情只会按需发生(即来自客户机的请求)。 但是,在使用过最低级别的
问题内容: 我有一个在EDT上运行的方法,在其中我想使它在新的(非EDT)线程上执行某些操作。我当前的代码如下: 问题答案: 您可以创建并启动一个新的Java线程,该线程从EDT线程中执行您的方法:
我想把线切成百分比。例如: -我的测试计划 -注册线程(此任务应为) -登录线程(此任务应为@) -搜索线程(此任务应为0) -添加新主题(此任务应为) 我怎么做这个分区? 谢谢
在将Android Studio更新到2.2版本(在Windows10上)之后,第二天早上,当gradle在任何项目上构建时,我都收到了这样的错误: 只允许从事件调度线程进行写访问 我提出这个问题只是为了与社区分享我的经验,因为我在这个问题上浪费了两个小时。