背景
一直在用Display.syncExec(Runnable)和Display.asyncExec(Runnable),只简单知道同步用前者,异步用后者,而且代码也工作的很好,今天把它后面的源代码都了一遍,有了更清楚的认识。
1,每个Display会关联一个Thread(在Shell或Eclipse环境中一般即为UI主线程),Display.readAndDispatch()方法可以用来处理OS发送过来的消息,也可以处理自身的消息队列,代码片段如下
public boolean readAndDispatch () { checkDevice (); lpStartupInfo = null; drawMenuBars (); runPopups (); if (OS.PeekMessage (msg, 0, 0, 0, OS.PM_REMOVE)) { if (!filterMessage (msg)) { OS.TranslateMessage (msg); OS.DispatchMessage (msg); } runDeferredEvents (); return true; } return runMessages && runAsyncMessages (false); }
2,每个Widget会关联到一个Display。特别对于Shell,可以构建UI,并进入消息循环。
Display display = new Display(); Shell shell = new Shell(display); shell.setMinimized(true); shell.open(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); }
3,一般用Display.syncExec(Runnable)和Display.asyncExec(Runnable)在UI主线程中同步或异步执行一段代码。同步和异步相关的两个线程,一个是该方法的调用线程,一个是和Display线程。当然调用线程本身也可以是和Display线程。
4,当调用线程和Display线程是同一线程时
(1)asyncExec(Runnable)将Runnable加入Display的消息队列,方法退出
(2)syncExec (Runnable)直接执行Runnable,方法退出
5,当调用线程和Display线程不是同一线程时
(1)asyncExec(Runnable)将Runnable加入Display的消息队列,方法退出。这和同一线程的情况一致。
(2)syncExec (Runnable)将Runnable加入Display的消息队列,然后等待Display将该Runnable执行完毕后,方法再退出。
protected void asyncExec (Runnable runnable) { if (runnable == null) { //TEMPORARY CODE if (!IS_CARBON) { display.wake (); return; } } addLast (new RunnableLock (runnable)); } protected void syncExec (Runnable runnable) { RunnableLock lock = null; synchronized (Device.class) { if (display == null || display.isDisposed ()) SWT.error (SWT.ERROR_DEVICE_DISPOSED); if (!display.isValidThread ()) { if (runnable == null) { display.wake (); return; } lock = new RunnableLock (runnable); /* * Only remember the syncThread for syncExec. */ lock.thread = Thread.currentThread(); addLast (lock); } } if (lock == null) { if (runnable != null) runnable.run (); return; } synchronized (lock) { boolean interrupted = false; while (!lock.done ()) { try { lock.wait (); } catch (InterruptedException e) { interrupted = true; } } if (interrupted) { Compatibility.interrupt(); } if (lock.throwable != null) { SWT.error (SWT.ERROR_FAILED_EXEC, lock.throwable); } } }
6,当在一个UI主线程中打开一个Dialog时,就会嵌套进入到另一个Shell的消息循环,但他们都用主线程的Display,都在主线程中。