我维护的Swing应用程序中的各种零星问题似乎是由它使用Toolkit.getDefaultToolkit().getSystemEventQueue().push(new AEventQueue())
用自己的自定义版本替换默认AWT事件队列的方式引起的。请参阅例如Swing应用程序中的线程和死锁。上面描述的问题已经解决,但我的测试(使用FESTSwing)现在往往会陷入死锁。
我怀疑最好的解决方案是在应用程序初始化开始时,在创建任何Swing组件之前,替换事件队列。然而,有一些依赖关系会让这变得很尴尬,所以目前我正试图找到一种安全的方法,在初始化后"推送"新的事件队列,即当前完成的队列。
我尝试过的两种方法是
- 使用CCD_ 2在EDT上推送新队列
- 初始化后,在主线程上推送新队列,并在使用
invokeLater()
以避免与旧EDT上已启动的任何队列发生死锁之后
阅读后我的期望https://stackoverflow.com/a/8965448/351885,第一种方法可能在Java7中工作,但在Java1.6中可能需要类似第二种方法。事实上,第二个在Java 1.6中确实有效,而在Java 7中,两者似乎都成功完成了,但运行速度非常缓慢。这可能只是一个FEST问题,因为应用程序本身似乎响应性很强。
所以我不得不使用第二种方法,它至少在Java 1.6中有效,但我想知道-如果有更安全的方法来实现这一点,因为如果事件在invokeLater
之后但在创建新队列之前出现在现有队列上,那么它似乎容易受到竞争条件的影响;-如果有不同的方法,我应该使用。
更多详细信息
第一个"解决方案"是这样的:
initApplication();
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new CustomEventQueue());
}
});
当使用Java 1.6编译和运行时,我不明白它在做什么。线程似乎在等待一个已经持有的锁:
"AWT-EventQueue-1" prio=10 tid=0x00007f9808001000 nid=0x6628 in Object.wait() [0x00007f986aa72000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000007d9961cf0> (a atlantis.gui.AEventQueue)
at java.lang.Object.wait(Object.java:502)
at java.awt.EventQueue.getNextEvent(EventQueue.java:490)
- locked <0x00000007d9961cf0> (a atlantis.gui.AEventQueue)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:247)
第二个"解决方案"是这样的:
initApplication();
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
logger.debug("Waiting for AWT event queue to be empty.");
}
});
} catch (InterruptedException e) {
logger.error("Interrupted while waiting for event queue.", e);
} catch (InvocationTargetException e) {
logger.error("Error while waiting for event queue.",e);
}
Toolkit.getDefaultToolkit().getSystemEventQueue().push(new CustomEventQueue());
如上所述,这在Java 1.6中似乎可以正常工作,但我不相信它真的是安全的。
我还没有弄清楚使用Java7时会发生什么,但主线程似乎花了很长时间休眠方法org.fest.swing.timing.Pause.pause()
,这就是为什么我怀疑这可能是一个特定于FEST的问题。
因为我看不出用新的EDT重置当前EDT的原因,所以我的问题是
1) 你有吗
-
Java解除锁定,内存不足。。。
-
RepaintManager异常,
2) 基本上你可以
-
用
Thread.sleep(int)
锁定当前EDT,用setVisible(false)
锁定引起的JComponent
, -
如果有EDT,那么你必须使用
invokeLater
,如果没有激活,那么你可以在invokeLater
和invokeAndWait
之间进行选择
代码
if (EventQueue.isDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
//some stuff
}
});
} else {
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
//some stuff
}
});
} catch (InterruptedException ex) {
Logger.getLogger(IsThereEDT.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(IsThereEDT.class.getName()).log(Level.SEVERE, null, ex);
}
}
3) 注意,invokeAndWait
必须从EDT中调用,否则会导致EDT exceptions
与当前EDT 解除锁定
4) 如果没有激活的EDT,那么push()
就没有理由与EventQueue
有关
5) 上述所有内容的简单测试代码。。
import java.awt.EventQueue;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class IsThereEDT {
private ScheduledExecutorService scheduler;
private AccurateScheduledRunnable periodic;
private ScheduledFuture<?> periodicMonitor;
private int taskPeriod = 30;
private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
private Date dateRun;
private JFrame frame1 = new JFrame("Frame 1");
public IsThereEDT() {
scheduler = Executors.newSingleThreadScheduledExecutor();
periodic = new AccurateScheduledRunnable() {
private final int ALLOWED_TARDINESS = 200;
private int countRun = 0;
private int countCalled = 0;
private int maxCalled = 10;
@Override
public void run() {
countCalled++;
if (countCalled < maxCalled) {
if (countCalled % 3 == 0) {
/*if (EventQueue.isDispatchThread()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
//some stuff
}
});
} else {
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
//some stuff
}
});
} catch (InterruptedException ex) {
Logger.getLogger(IsThereEDT.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvocationTargetException ex) {
Logger.getLogger(IsThereEDT.class.getName()).log(Level.SEVERE, null, ex);
}
}*/
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println("Push a new event to EDT");
frame1.repaint();
isThereReallyEDT();
}
});
} else {
if (this.getExecutionTime() < ALLOWED_TARDINESS) {
countRun++;
isThereReallyEDT(); // non on EDT
}
}
} else {
System.out.println("Terminating this madness");
System.exit(0);
}
}
};
periodicMonitor = scheduler.scheduleAtFixedRate(periodic, 0, taskPeriod, TimeUnit.SECONDS);
periodic.setThreadMonitor(periodicMonitor);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
isThereReallyEDT();
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.getContentPane().add(new JLabel("Hello in frame 1"));
frame1.pack();
frame1.setLocation(100, 100);
frame1.setVisible(true);
}
});
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(IsThereEDT.class.getName()).log(Level.SEVERE, null, ex);
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame2 = new JFrame("Frame 2");
frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame2.getContentPane().add(new JLabel("Hello in frame 2"));
frame2.pack();
frame2.setLocation(200, 200);
frame2.setVisible(true);
isThereReallyEDT();
}
});
}
private void isThereReallyEDT() {
dateRun = new java.util.Date();
System.out.println(" Time at : " + sdf.format(dateRun));
if (EventQueue.isDispatchThread()) {
System.out.println("EventQueue.isDispatchThread");
} else {
System.out.println("There isn't Live EventQueue.isDispatchThread, why any reason for that ");
}
if (SwingUtilities.isEventDispatchThread()) {
System.out.println("SwingUtilities.isEventDispatchThread");
} else {
System.out.println("There isn't Live SwingUtilities.isEventDispatchThread, why any reason for that ");
}
System.out.println();
}
public static void main(String[] args) {
IsThereEDT isdt = new IsThereEDT();
}
}
abstract class AccurateScheduledRunnable implements Runnable {
private ScheduledFuture<?> thisThreadsMonitor;
public void setThreadMonitor(ScheduledFuture<?> monitor) {
this.thisThreadsMonitor = monitor;
}
protected long getExecutionTime() {
long delay = -1 * thisThreadsMonitor.getDelay(TimeUnit.MILLISECONDS);
return delay;
}
}