Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 创建事件分派线程安全信号量_Java_Multithreading_Swing_Awt_Event Dispatch Thread - Fatal编程技术网

Java 创建事件分派线程安全信号量

Java 创建事件分派线程安全信号量,java,multithreading,swing,awt,event-dispatch-thread,Java,Multithreading,Swing,Awt,Event Dispatch Thread,我一直在尝试制作一个二进制信号量,它能够安全地阻止在事件调度线程(EDT)上运行的方法的执行,而不会实际阻止线程处理更多事件。这在一开始似乎是不可能的,但Java有一些与此相关的内置功能,但我无法让它正常工作 用例 当前,如果显示EDT中的模式摆动对话框,它将显示为阻止EDT(因为显示模式对话框的方法在对话框关闭之前不会继续到下一行),但实际上,有一些隐藏的魔法使EDT进入一个新的事件循环,该循环将继续发送事件,直到模式对话框关闭 我的团队目前拥有的应用程序从swing迁移到JavaFX的速度非

我一直在尝试制作一个二进制信号量,它能够安全地阻止在事件调度线程(EDT)上运行的方法的执行,而不会实际阻止线程处理更多事件。这在一开始似乎是不可能的,但Java有一些与此相关的内置功能,但我无法让它正常工作

用例 当前,如果显示EDT中的模式摆动对话框,它将显示为阻止EDT(因为显示模式对话框的方法在对话框关闭之前不会继续到下一行),但实际上,有一些隐藏的魔法使EDT进入一个新的事件循环,该循环将继续发送事件,直到模式对话框关闭

我的团队目前拥有的应用程序从swing迁移到JavaFX的速度非常慢(这是一个有点棘手的过渡),我希望能够以显示swing模式对话框的相同方式显示AWT事件调度线程中的模式JavaFX对话框。似乎拥有某种EDT安全的信号灯可以满足这个用例,并且可能在将来的其他用途中派上用场

方法
java.awt.EventQueue.createSecondaryLoop()
是一种创建
SecondaryLoop
对象的方法,然后可以使用该对象启动新的事件处理循环。调用
SecondaryLoop.enter()
时,调用将在处理新事件循环时被阻止(请注意,调用将被阻止,但线程不会被阻止,因为它将在事件处理循环中继续)。新的事件循环将继续,直到您调用
SecondaryLoop.exit()
(这不完全正确,请参阅我的)

因此,我创建了一个信号量,其中一个阻塞调用在等待正常线程的闩锁或进入EDT的二次循环时获取结果。要获取的每个阻塞调用还将添加一个解除阻塞操作,以便在释放信号量时调用(对于普通线程,它只是减少锁存,对于EDT,它退出二次循环)

这是我的密码:


导入java.awt.EventQueue;
导入java.awt.SecondaryLoop;
导入java.awt.Toolkit;
导入java.util.Stack;
导入java.util.concurrent.CountDownLatch;
导入java.util.concurrent.Semaphore;
@抑制警告(“串行”)
公共类EventDispatchThreadSafeBarySemaphore扩展信号量{
/**释放信号量时用于取消阻止线程的操作。
*必须是堆栈,因为必须在中退出次循环
*与为解除阻止而输入的顺序相反
*进入循环的方法的执行。
*/
私有堆栈释放操作=新堆栈();
私有布尔信号量readyacquired=false;
public EventDispatchThreadSafeBarySemaphore()公共事件调度线程安全二进制信号量{
超级(0);
}
@凌驾
公共布尔值isFair(){
返回false;
}
@凌驾
public void acquire()引发InterruptedException{
Runnable blockingOperation=()->{};
已同步(此){
if(信号量ReadyAcquired){
//我们没有获取信号量,需要设置一个要执行的操作
//当我们等待信号量和另一个线程的操作时
//在信号量可用时执行以解除阻止
if(EventQueue.isDispatchThread()){
//对于EDT,我们不希望实际阻塞,而是将进入一个新的循环,该循环将继续
//处理AWT事件。
SecondaryLoop temporaryAwtLoop=Toolkit.getDefaultToolkit().getSystemEventQueue().CreateSondaryLoop();
添加(()->temporaryAwtLoop.exit());
阻塞操作=()->{
如果(!temporaryAwtLoop.enter()){
//我不认为我们会遇到这种情况,但我现在把它留在这里,用于调试目的
System.err.println(“未能进入事件循环”);
}
};
}
否则{
//非分派线程稍微简单一些,我们只需等待闩锁
CountDownLatch blockedLatch=新的CountDownLatch(1);
添加(()->blockedLatch.countDown());
阻塞操作=()->{
试一试{
阻塞闩锁。等待();
}捕捉(中断异常e){
//一旦我掌握了基本知识,我会担心如何更好地处理这个问题
e、 printStackTrace();
}
};
}
}
否则{
信号量readyacquired=true;
}
}
//这个部分必须在同步块之外执行,这样我们就不会阻塞
//如果此语句被阻止时EDT尝试获取信号量,则返回EDT
blockingOperation.run();
}
@凌驾
公开无效释放(){
已同步(此){
if(releaseOperations.size()>0){
//释放最后一个阻塞的线程
releaseOperations.pop().run();
}
否则{
信号量readyacquired=false;
}
}
}
}
下面是我的相关JUnit测试代码(很抱歉代码太大了,这是迄今为止我能想到的最小可验证示例):

公共类TestEventDispatchThread安全二进制信号量{
私有静态EventDispatchThreadSafeBarySemaphore信号量;
//看https://stackoverflow.com/questions/58192008/secondaryloop-enter-not-blocking-until-exit-is-called-on-the-edt
//我们为什么需要这个计时器
专用静态定时器