什么是新的Runnable(){}?
new Runnable() {
public void run() {
createAndShowGUI();
}
};
这声明了一个匿名类并实例化它的新实例.它基本上相当于:
class Creator implements Runnable {
public void run() {
createAndShowGUI();
}
}
new Creator();
在Java 8 lambdas之前,匿名类是一种进行函数式编程的方法.将Runnable传递给invokeLater就像传递一个EDT可以随时执行的函数(通过调用run on).
invokeLater对Runnable做了什么?
最初,它所做的只是创建一个事件来包装它(一个InvocationEvent)并将它放在队列的末尾.
排队事件后,invokeLater会通知EDT(如果等待则会唤醒它). EDT自己的run方法是一个处理事件的无限循环.它看起来像这样(非常复述):
public void run() {
while(true) {
EventQueue eq = getEventQueue();
synchronized(eq) {
while(eq.hasNextEvent()) {
processOneEvent(eq.getNextEvent());
}
try {
eq.wait();
} catch(InterruptedException ie) {}
}
}
}
当EDT到达新的InvocationEvent时,它调用Runnable上的runnable,它调用createAndShowGUI.
因此,将Runnable传递给invokeLater或invokeAndWait可以让您在EDT上运行任何所需的代码.
跑多久叫?
在大多数情况下,立即或几乎立即.美国东部时间非常敏感. ‘invokeLater’的’Later’部分只是暗示我们:
> run是异步执行的.在处理事件之前,调用invokeLater的线程可能会继续通过调用.
>可以先处理其他事件.
当然,如果需要同步调用run,则invokeAndWait作为替代方案存在. (虽然应该注意,如果invokeAndWait在新的InvocationEvent之前排队,它们也可能导致处理其他事件.)
异步
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.println("hello");
}
});
System.out.println("world");
这可能会打印
hello
world
它可能会打印
world
hello
因为在处理事件之前(或甚至在处理事件)之前,调用线程可能会继续也可能不会继续.这取决于系统的线程调度程序.
同步
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
System.out.println("hello");
}
});
System.out.println("world");
这肯定会打印出来
hello
world
因为调用线程将在继续之前等待运行完成(除非抛出异常).
invokeAndWait使用等待和通知方案来实现此目的.创建一个monitor对象并将其提供给InvocationEvent.发布事件后invokeAndWait调用等待,并且在EDT上运行完成后InvocationEvent调用notifyAll.等待和通知方案是无法在EDT上调用invokeAndWait的原因. EDT没有办法在一个事件中间停止处理另一个事件.
如果多个事件排队会发生什么?
EDT按照它们排队的顺序并根据它们的优先级一次处理一个事件.某些事件也可以合并(常规的InvocationEvent不会).大多数事件都是正常的优先PaintEvent(类似于调用重绘)通常是低优先级的,并且某些系统事件具有更高的优先级.
在您给出的具体示例中:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
SwingUtilities.invokeLater(new Runnable() {
public void run() {
doSomethingElse();
}
});
由于它们是相同类型的事件和相同的优先级,因此doSomethingElse事件将在createAndShowGUI事件完成后处理.
同样,如果这样做了:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.out.println("world");
}
});
System.out.println("hello");
}
});
那将打印出来
hello
world
因为世界Runnable在hello Runnable完成后运行.