- 전체
- JAVA 일반
- JAVA 수학
- JAVA 그래픽
- JAVA 자료구조
- JAVA 인공지능
- JAVA 인터넷
- Java Framework
- Java GUI (AWT,SWING,SWT,JFACE)
- SWT and RCP (web RAP/RWT)[eclipse], EMF
SWT: Respond to Long Running Tasks
Most Swing developers are aware of the fact that Swing (and AWT) operate on a single-threaded model, and any changes that are to happen to the UI, should happen in the event dispatch thread. This is a fairly commonly accepted and understood programming model. The biggest difficulty comes in when you are executing fairly intensive code in the UI thread, and suddenly realize that the application is no longer responding to button presses, split-pane resizing, keystrokes, etc. In addition, in pre-Mustang releases (Java 5 and down), the application even ceases to paint. The commonly accepted solution is for those long running operations to be executed on a background thread, leaving the event dispatch thread open to respond to user interaction, but then asking for a small unit-of-work to be executed *back* on the event dispatch thread, to ensure that any UI updates occur from the correct thread.
Typically this is performed by, in the code running in the background thread, creating a
// Note - EventQueue could also be replaced with 'SwingUtilities' in the example below. // Code in background thread. doSomeExpensiveProcessing(); EventQueue.invokeLater(new Runnable() { public void run() { someLabel.setText("Complete!"); } });
In addition, when you begin modularizing and breaking apart your code, a certain block of code may not be in a position to truly be aware if it is running on the event dispatch thread. If it is, it may be beneficial to execute the visual update immediately, rather than queueing it for later.
// Note - EventQueue could also be replaced with 'SwingUtilities' in the example below. // Code in background thread. doSomeExpensiveProcessing(); Runnable r = new Runnable() { public void run() { someLabel.setText("Complete!"); } }; if(EventQueue.isEventDispatchThread()) { r.run(); } else { EventQueue.invokeLater(r); }
Finally, if you need to ensure (in this background thread) that the UI was updated appropriately, you can ask Swing to let you wait until it is done invoking the runnable:
// Note - EventQueue could also be replaced with 'SwingUtilities' in the example below. // Code in background thread. doSomeExpensiveProcessing(); Runnable r = new Runnable() { public void run() { someLabel.setText("Complete!"); } }; if(EventQueue.isEventDispatchThread()) { r.run(); } else { try { EventQueue.invokeAndWait(r); } catch(InterruptedException e) { /* handle */ } catch(InvocationTargetException e) { /* handle */ } }
I'm not here to talk about Swing however. I'm here to talk about SWT. So why all the subterfuge? Well, the truth is, SWT is *also* essentially a single-threaded UI toolkit (it really does differ, but for the sake of a single display discussion, you can believe me and be happy). It suffers from the same effective problems inherent in Swing as seen above. In fact, most anyone who has done multi-threaded SWT programming, and was somewhat careless or forgetful at sometime, has probably seen this stack trace:
org.eclipse.swt.SWTException: Invalid thread access at org.eclipse.swt.SWT.error(SWT.java:2691) at org.eclipse.swt.SWT.error(SWT.java:2616) at org.eclipse.swt.SWT.error(SWT.java:2587) ...
SWT does make a point to fail-fast when it comes to threading problems; so at least the typical problems don't go unnoticed until production. The question is, however, what do you do if you need to update a label/button/super-duper-control in SWT from a background thread? Well, it's surprisingly similar to Swing:
// Code in background thread. doSomeExpensiveProcessing(); Display.getDefault().asyncExec(new Runnable() { public void run() { someSwtLabel.setText("Complete!"); } });
Note that Display objects are keyed by the thread they belong to - in a single display environment (most applications), you don't have to explicitly worry about dispatching your runnable to the *right* display object (the call to You may notice, however, that there is no
boolean isDisplayThread1 = Display.getCurrent() != null; // current will be null if current thread doesn't belong to a display object boolean isDisplayThread2 = Display.findDisplay(Thread.currentThread()) != null; // effectively the same as the call above. boolean isDisplayThread3 = Display.getDefault().getThread() != Thread.currentThread(); // match the current thread with the default display thread.
There are more than likely other ways to do this, but as you can see, it isn't particularly complicated - each of these solutions is based in the world of checking the current thread, and seeing if there is a display object registered for it.
// Code in background thread. doSomeExpensiveProcessing(); Runnable r = new Runnable() { public void run() { someSwtLabel.setText("Complete!"); } }; if(Display.getCurrent() != null) { r.run(); } else { Display.getDefault().asyncExec(r); }
Finally, the display class also supports synchronous execution:
// Code in background thread. doSomeExpensiveProcessing(); Runnable r = new Runnable() { public void run() { someSwtLabel.setText("Complete!"); } }; if(Display.getCurrent() != null) { r.run(); } else { Display.getDefault().syncExec(r); // notice SYNC exec }
Finally, some things to note:
Until next time, R.J. Lorimer |
[출처] http://www.javalobby.org/java/forums/t43753.html
광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.