如果EDT是一个单独的线程,为什么在这个例子中invokeLater等待主线程完成?
所以如果 Event Dispatch Thread 是一个独立于主线程的线程,那让我觉得下一个代码会输出
Before
Runnable
true
After
Before
Runnable
true
After
Before
Runnable
true
After
但是当我运行它时,就好像 EDT 在运行invokeLater(..)方法内的代码块之前等待主线程完成。输出是:
Before
After
Runnable
true
编码:
但是,如果我替换invokeLater(..)为invokeAndWait(..),那么我得到
这让我觉得 EDT 并不是一个真正的独立线程,或者至少在这个例子中它的行为或只是在我看来不是。你怎么解释这个?
回答
你怎么解释这个?
当您尝试解释涉及线程的观察行为时,几乎适用于每个问题的相同解释:
线程是复杂的野兽,通常添加代码来观察正在发生的事情会影响线程,线程作为一般概念是不可重复的(事情取决于您的音乐播放器中播放的歌曲到月相),并且它不会不会按照您认为的方式工作,所提供的解释和心理模型过于简单化,站不住脚。
这不是太辛苦在这里解释,幸运的是:
-
是的,它确实是一个单独的线程。你可以随时跑去
Thread.currentThread()看这个。 -
线程不是一些巫毒魔法瞬间的东西,你的 CPU 也不是秘密地一批完全独立的计算机。
该invokeLater调用接收您的代码,将其添加到队列中,然后 ping EDT 以唤醒并处理该队列,该队列现在包含 1 个项目。这个队列有很多流量;当您将另一个窗口移到您的窗口上时,EDT 会重新绘制 ping。当您单击一个按钮时,它也会被添加到队列中,等等。
无论该队列上的流量如何,唤醒线程的行为都不是即时的。您的主线程开始写入After 的速度比您的计算机系统实际唤醒该线程的速度要快得多(不仅仅是人类可以观察到它,计算机的运行速度比我们用眼球观察到的速度快几百万倍)。
在那里投炸弹看看效果。例如,在Thread.sleep(1000);之前添加sysout("After");并观察会发生什么。
当然,您会观察您在使用invokeAndWait时所做的事情 - 这将做完全相同的事情(将您的代码添加到队列中,然后向线程发送 ping 以唤醒),但它会冻结您的主线程。发送到 EDT 的代码将更新一些内部布尔值(“是的,我已经运行到最后”,并将 ping 发送回主线程以唤醒,检查该布尔值,然后继续)。因此,在您的代码(打印 Runnable 和 true)运行之前,它无法继续。
换句话说:
你的第二个片段总是输出你写的东西。
你的第一个片段会输出,谁知道呢。系统可以自由打印B/R/t/A, 或B/A/R/t,甚至B/R/A/t在极少数情况下。作为一个额外的问题,System.out它很重并且会导致同步,所以如果你在分析线程的同时打印,你观察到的东西通常是完全不相关的。
- One more thing: In OP's example, the `...invokeLater(...)` call is the first (and only) Swing call in the entire program. That means, the EDT does not even _exist_ until `invokeLater` creates it. I haven't seen the source code, so I don't know how much initialization the EDT does on startup before it even looks at the task queue. Could be significant.