我一直在尝试创建一个二进制信号量,它能够安全地阻止在事件调度线程(EDT)上运行的方法的执行,而不会实际阻止线程处理更多事件。乍一看这似乎是不可能的,但 Java 有一些与此相关的内置功能,但我无法完全让它工作。
目前,如果您从 EDT 显示模态摆动对话框,它似乎会阻止 EDT(因为显示模态对话框的方法在对话框关闭之前不会继续到下一行),但实际上有一些问题-hood 魔法,使 EDT 进入一个新的事件循环,该循环将继续调度事件,直到模式对话框关闭。
我的团队目前的应用程序正在非常缓慢地从 swing 迁移到 JavaFX(这是一个有点棘手的过渡),并且我希望能够以与显示 swing 模态对话框相同的方式从 AWT 事件调度线程显示模态 JavaFX 对话框。似乎拥有某种 EDT 安全信号量就可以满足这个用例,并且可能在以后的其他用途中派上用场。
java.awt.EventQueue.createSecondaryLoop()
是一种创建SecondaryLoop
对象的方法,然后您可以使用该对象来启动新的事件处理循环。当您调用 时SecondaryLoop.enter()
,调用将在处理新的事件循环时阻塞(请注意,调用会阻塞,但线程不会阻塞,因为它正在事件处理循环中继续)。新的事件循环将继续,直到您调用为止SecondaryLoop.exit()
(这并不完全正确,请参阅我的相关 SO 问题)。
因此,我创建了一个信号量,其中阻塞调用会导致等待正常线程的锁存器,或者进入 EDT 的辅助循环。每个对 acquire 的阻塞调用还会添加一个在释放信号量时调用的解锁操作(对于普通线程,它只是递减锁存器,对于 EDT,它退出辅助循环)。
这是我的代码:
import java.awt.EventQueue;
import java.awt.SecondaryLoop;
import java.awt.Toolkit;
import java.util.Stack;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Semaphore;
@SuppressWarnings("serial")
public class EventDispatchThreadSafeBinarySemaphore extends Semaphore{
/** Operations used to unblock threads when a semaphore is released.
* Must be a stack because secondary loops have to be exited in the
* reverse of the order in which they were entered in order to unblock
* the execution of the method that entered the loop.
*/
private Stack<Runnable> releaseOperations = new Stack<>();
private boolean semaphoreAlreadyAcquired = false;
public EventDispatchThreadSafeBinarySemaphore() {
super(0);
}
撒科打诨
相关分类