public
void
dispatch() {
if (catchExceptions) {
try {
runnable.run();
}
catch (Throwable t) {
if (t instanceof Exception) {
exception = (Exception) t;
}
throwable = t;
}
}
else {
runnable.run();
}
if (notifier != null ) {
synchronized (notifier) {
notifier.notifyAll();
}
}
}
runnable.run();而如何将我们写的getFileLock加入的那个EventQueue中的呢?当然是SwingUtilities.invokeAndWait(new getFileLock());看JDK代码:if (catchExceptions) {
try {
runnable.run();
}
catch (Throwable t) {
if (t instanceof Exception) {
exception = (Exception) t;
}
throwable = t;
}
}
else {
runnable.run();
}
if (notifier != null ) {
synchronized (notifier) {
notifier.notifyAll();
}
}
}
public
static
void
invokeAndWait(Runnable runnable)
throws InterruptedException, InvocationTargetException {
if (EventQueue.isDispatchThread()) {
throw new Error( " Cannot call invokeAndWait from the event dispatcher thread " );
}
class AWTInvocationLock {}
Object lock = new AWTInvocationLock();
InvocationEvent event =
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock,
true );
synchronized (lock) {
Toolkit.getEventQueue().postEvent(event);
lock.wait();
}
throws InterruptedException, InvocationTargetException {
if (EventQueue.isDispatchThread()) {
throw new Error( " Cannot call invokeAndWait from the event dispatcher thread " );
}
class AWTInvocationLock {}
Object lock = new AWTInvocationLock();
InvocationEvent event =
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock,
true );
synchronized (lock) {
Toolkit.getEventQueue().postEvent(event);
lock.wait();
}
Toolkit.getEventQueue()。postEvent(event);把我们写的getFileLock 塞进了EventQueue.这下读者对EDT有个认识了吧。
1. EDT 只有一个线程, 虽然getFileLock是实现Runnable接口,它调用的时候不是star方法启动新线程,而是直接调用run方法。
2. invokeAndWait将你写的getFileLock塞到EventQueue中。
3. Swing 事件机制采用Product Consumer模式 EDT不断的取EventQueue中的事件执行(消费者)。其他线程可以将事件塞入EventQueue中,比如鼠标点击Button是,将注册在BUttion的事件塞入EventQueue中。
所以我们将getFileLock作为事件插入进去后 EDT分发是调用Thread.sleep(Integer.MAX_VALUE)就睡觉了,无暇管塞入EventQueue的其他事件了,比如关闭窗体。
所以绝对不能将持有锁的逻辑塞到EventQueue,而应该放到外边main线程或者其他线程里面。
提到invokeAndWait,还必须说说invokelater 这两个区别在哪里呢?
invokeAndWait与invokelater区别: 看JDK代码:
public
static
void
invokeLater(Runnable runnable) {
Toolkit.getEventQueue().postEvent(
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
}
Toolkit.getEventQueue().postEvent(
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
}
public
static
void
invokeAndWait(Runnable runnable)
throws InterruptedException, InvocationTargetException {
if (EventQueue.isDispatchThread()) {
throw new Error( " Cannot call invokeAndWait from the event dispatcher thread " );
}
class AWTInvocationLock {}
Object lock = new AWTInvocationLock();
InvocationEvent event =
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock,
true );
synchronized (lock) {
Toolkit.getEventQueue().postEvent(event);
lock.wait();
}
Throwable eventThrowable = event.getThrowable();
if (eventThrowable != null ) {
throw new InvocationTargetException(eventThrowable);
}
}
throws InterruptedException, InvocationTargetException {
if (EventQueue.isDispatchThread()) {
throw new Error( " Cannot call invokeAndWait from the event dispatcher thread " );
}
class AWTInvocationLock {}
Object lock = new AWTInvocationLock();
InvocationEvent event =
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable, lock,
true );
synchronized (lock) {
Toolkit.getEventQueue().postEvent(event);
lock.wait();
}
Throwable eventThrowable = event.getThrowable();
if (eventThrowable != null ) {
throw new InvocationTargetException(eventThrowable);
}
}
invokeAndWait: 当在Main方法中调用SwingUtils.invokeAndWait 后,看代码片段:
synchronized (lock) {
Toolkit.getEventQueue().postEvent(event);
lock.wait();
}
main线程获得lock 后就wait()了,直到事件分发线程调用lock对象的notify唤醒main线程,否则main 就干等着吧。
这下明白了吧!
总之,对于我们问题最简单的方法就是是main线程里,或者在其他线程里处理。