如果我正确理解了您的问题,您会想知道为什么不能这样做:
public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { showGUI(); } }); counter.start();}之所以无法执行此操作,是因为调度程序不做任何保证……仅因为您调用了
showGUI()之后又调用了
counter.start()它并不意味着in中的代码
showGUI()将在.run方法中的代码之前执行
counter。
这样想:
- invokeLater的
启动一个线程和线程的调度,其任务是在美国东部时间异步事件 产生 的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



