/[debian]/libspin-java/branches/upstream/current/src/site/xdoc/problem.xml
ViewVC logotype

Contents of /libspin-java/branches/upstream/current/src/site/xdoc/problem.xml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 680 - (show annotations)
Sun Apr 1 14:25:01 2007 UTC (14 years, 3 months ago) by gregoa
File MIME type: text/xml
File size: 19865 byte(s)
[svn-upgrade] Integrating new upstream version, libspin-java (1.5)
1 <document>
2 <properties>
3 <author email="sven@users.sourceforge.net">Sven Meier</author>
4 <title>Spin your Swing</title>
5 </properties>
6 <body>
7 <section name="The Problem">
8 <subsection name="Standard Swing">
9 <p>
10 In this section we take a look at a naive <acronym title="Graphical user interface">GUI</acronym> implementation that shows how Swing freezes in case the application programmer doesn't take any special actions against it. We also describe the problem of calls into Swing components triggered by any other thread than the event dispatch thread (EDT). <br/>
11 Swing is not designed for multi threading, so let us first recall the single threading rule of every Swing <acronym title="Graphical user interface">GUI</acronym>:
12 </p>
13 <blockquote>
14 <cite>Access to a (visible) Swing component has to occur in the event dispatch thread.</cite>
15 </blockquote>
16 <p>
17 The <acronym title="Event Dispatch Thread">EDT</acronym> is responsible to process all <acronym title="Graphical user interface">GUI</acronym> related events, e.g. notifying listeners of user input, repainting dirty regions or updated areas. All these events are enqueued and treated sequentially - if one of them takes a long time to be processed, all further events will have to wait.
18 </p>
19 <p>
20 Throughout the next sections we'll put the code of a Swing <acronym title="Graphical user interface">GUI</acronym> component and a non visual bean side by side. The bean encapsulates an extensive calculation that is used by multiple threads. Code run on the <acronym title="Event Dispatch Thread">EDT</acronym> is <span class="onEDT">shown in green</span> and code called by any other thread is <span class="offEDT">shown in red</span>.
21 </p>
22 <p>
23 As you can see in the following code, <code>GUI.java</code> calls the method <code>getValue()</code> on the bean when an action is performed. The <acronym title="Event Dispatch Thread">EDT</acronym> is routed from the <acronym title="Graphical user interface">GUI</acronym> to the bean. While it is performing its calculations no further swing events can be processed - the <acronym title="Graphical user interface">GUI</acronym> freezes.<br/>
24 One of these queued events is the repaint of the label triggered by <code>label.setText("...")</code>. When <code>getValue()</code> returns, the text of the label is changed again before the previous text was painted. So in fact <code>"..."</code> is never seen:
25 </p>
26
27 <!--
28 public void actionPerformed(ActionEvent e)
29 {
30 label.setText("...");
31 label.setText(bean.getValue());
32 }
33
34 public void propertyChange(PropertyChangeEvent ev)
35 {
36 label.setText((String)ev.getNewValue());
37 }
38 -->
39 <div class="java left">
40 <h3 class="java">GUI.java</h3>
41 <code class="java"><span class="java4">public </span><span class="java9">void </span><span class="java10">actionPerformed</span><span class="java8">(</span><span class="java10">ActionEvent e</span><span class="java8">)<br />
42 {<br />
43 </span><span class="onEDT">&#xA0; <span class="java10">label.setText</span><span class="java8">(</span><span class="java5">&#34;...&#34;</span><span class="java8">)</span><span class="java10">;<br />
44 &#xA0; label.setText</span><span class="java8">(</span><span class="java10">bean.getValue</span><span class="java8">())</span><span class="java10">;<br />
45 </span></span><span class="java8">}<br />
46 <br />
47 <br />
48 </span><span class="java4">public </span><span class="java9">void </span><span class="java10">propertyChange</span><span class="java8">(</span><span class="java10">PropertyChangeEvent ev</span><span class="java8">)<br />
49 {<br />
50 </span><span class="offEDT">&#xA0; <span class="java10">label.setText</span><span class="java8">((</span><span class="java10">String</span><span class="java8">)</span><span class="java10">ev.getNewValue</span><span class="java8">())</span><span class="java10">;<br />
51 </span></span><span class="java8">}</span>
52 <br />&#xA0;</code></div>
53
54 <!--
55 public String getValue()
56 {
57 String value;
58 // extensive calculation
59 return value;
60 }
61
62 public void setValue(String value)
63 {
64 this.value = value;
65 firePropertyChange(value);
66 }
67 -->
68 <div class="java right">
69 <h3 class="java">BeanImpl.java</h3>
70 <code class="java"><span class="java4">public </span><span class="java10">String getValue</span><span class="java8">()<br />
71 {<br />
72 </span><span class="onEDT">&#xA0; <span class="java10">String value;<br />
73 &#xA0; </span><span class="java3">// extensive calculation<br />
74 &#xA0; </span><span class="java4">return </span><span class="java10">value;<br />
75 </span></span><span class="java8">}<br />
76 <br />
77 </span><span class="java4">public </span><span class="java9">void </span><span class="java10">setValue</span><span class="java8">(</span><span class="java10">String value</span><span class="java8">)<br />
78 {<br />
79 </span><span class="offEDT">&#xA0; <span class="java4">this</span><span class="java10">.value = value;<br />
80 &#xA0; firePropertyChange</span><span class="java8">(</span><span class="java10">value</span><span class="java8">)</span><span class="java10">;<br />
81 </span></span><span class="java8">}</span></code></div>
82
83 <div class="clear"/>
84
85 <p>
86 What happens if <code>setValue()</code> is invoked on the bean on another thread. The listeners are notified (the class <code>GUI</code> implements <code>java.beans.PropertyChangeListener</code> and is registered as a listener for changes of the bean), triggering a call to <code>propertyChange()</code> on the <acronym title="Graphical user interface">GUI</acronym>. The text of the label is altered on the calling thread, violating the Swing threading rule.
87 </p>
88 <p>
89 The color distribution gives a hint where to search for problems of this implementation:<br/>
90 <span class="onEDT">Green lines</span> of code in <code>BeanImpl.java</code> result in a <acronym title="Graphical user interface">GUI</acronym> freeze, <span class="offEDT">red lines</span> in <code>GUI.java</code> show a violation to the Swing threading rule.
91 </p>
92 </subsection>
93 <subsection name="Working Thread">
94 <p>
95 One obvious solution to the problems seen in the previous section is to shift the invocation of <code>getValue()</code> from the <acronym title="Event Dispatch Thread">EDT</acronym> to a separate thread. When this method returns we must not propagate the result to a Swing component though. We have to return control to the <acronym title="Event Dispatch Thread">EDT</acronym> instead. This can be achieved via <code>SwingUtilities.invokeLater()</code> which will use our Runnable to correctly change the label's text on the <acronym title="Event Dispatch Thread">EDT</acronym>:
96 </p>
97
98 <!--
99 public void actionPerformed(ActionEvent e)
100 {
101 label.setText("...");
102 new Thread(new Runnable()
103 {
104 public void run()
105 {
106 final String value = bean.getValue();
107 SwingUtilities.invokeLater(new Runnable()
108 {
109 public void run()
110 {
111 label.setText(value);
112 }
113 });
114 }
115 }).start();
116 }
117
118 public void propertyChange(final PropertyChangeEvent ev)
119 {
120 SwingUtilities.invokeLater(new Runnable()
121 {
122 public void run()
123 {
124 label.setText((String)ev.getNewValue());
125 }
126 });
127 }
128 -->
129 <div class="java left">
130 <h3 class="java">GUI.java</h3>
131 <code class="java"><span class="java4">public </span><span class="java9">void </span><span class="java10">actionPerformed</span><span class="java8">(</span><span class="java10">ActionEvent e</span><span class="java8">)<br />
132 {<br />
133 </span><span class="onEDT">&#xA0; <span class="java10">label.setText</span><span class="java8">(</span><span class="java5">&#34;...&#34;</span><span class="java8">)</span><span class="java10">;<br />
134 &#xA0; </span><span class="java4">new </span><span class="java10">Thread</span><span class="java8">(</span><span class="java4">new </span><span class="java10">Runnable</span><span class="java8">()<br />
135 &#xA0; {<br /></span></span>
136 &#xA0;&#xA0;&#xA0; <span class="java4">public </span><span class="java9">void </span><span class="java10">run</span><span class="java8">()<br />
137 &#xA0;&#xA0;&#xA0; {</span><br />
138 <span class="offEDT">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <span class="java4">final </span><span class="java10">String value = bean.getValue</span><span class="java8">()</span><span class="java10">;<br />
139 &#xA0;&#xA0;&#xA0;&#xA0;&#xA0; SwingUtilities.invokeLater</span><span class="java8">(</span><span class="java4">new </span><span class="java10">Runnable</span><span class="java8">()<br />
140 &#xA0;&#xA0;&#xA0;&#xA0;&#xA0; {</span></span><br />
141 &#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <span class="java4">public </span><span class="java9">void </span><span class="java10">run</span><span class="java8">()<br />
142 &#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; {</span><br />
143 <span class="onEDT">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <span class="java10">label.setText</span><span class="java8">(</span><span class="java10">value</span><span class="java8">)</span><span class="java10">;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;</span></span><br />
144 &#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <span class="java8">}</span><br />
145 <span class="offEDT">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <span class="java8">})</span><span class="java10">;</span></span><br />
146 &#xA0;&#xA0;&#xA0; <span class="java8">}<br /></span>
147 <span class="onEDT">&#xA0; <span class="java8">}})</span><span class="java10">.start</span><span class="java8">()</span><span class="java10">;<br />
148 </span></span><span class="java8">}<br />
149 <br />
150 </span><span class="java4">public </span><span class="java9">void </span><span class="java10">propertyChange</span><span class="java8">(</span><span class="java4">final </span><span class="java10">PropertyChangeEvent ev</span><span class="java8">)<br />
151 {<br />
152 </span><span class="offEDT">&#xA0; <span class="java10">SwingUtilities.invokeLater</span><span class="java8">(</span><span class="java4">new </span><span class="java10">Runnable</span><span class="java8">()<br />
153 &#xA0; {<br /></span></span>
154 &#xA0;&#xA0;&#xA0; <span class="java4">public </span><span class="java9">void </span><span class="java10">run</span><span class="java8">()<br />
155 &#xA0;&#xA0;&#xA0; {</span><br />
156 <span class="onEDT">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <span class="java10">label.setText</span><span class="java8">((</span><span class="java10">String</span><span class="java8">)</span><span class="java10">ev.getNewValue</span><span class="java8">())</span><span class="java10">;</span></span><br />
157 &#xA0;&#xA0;&#xA0; <span class="java8">}</span><br />
158 <span class="offEDT">&#xA0; <span class="java8">})</span><span class="java10">;</span></span><br />
159 <span class="java8">}</span></code></div>
160
161 <!--
162 public String getValue()
163 {
164 String value;
165 // extensive calculation
166 return value;
167 }
168
169 public void setValue(String value)
170 {
171 this.value = value;
172 firePropertyChange(value);
173 }
174 -->
175 <div class="java right">
176 <h3 class="java">BeanImpl.java</h3>
177 <code class="java"><span class="java4">public </span><span class="java10">String getValue</span><span class="java8">()<br />
178 {</span><br />
179 <span class="offEDT">&#xA0; <span class="java10">String value;<br />
180 &#xA0; </span><span class="java3">// extensive calculation<br />
181 &#xA0; </span><span class="java4">return </span><span class="java10">value;</span></span><br />
182 <span class="java8">}<br />
183 <br />
184 <br />
185 <br />
186 <br />
187 <br />
188 <br />
189 <br />
190 <br />
191 <br />
192 <br />
193 <br />
194 <br />
195 <br />
196 </span><span class="java4">public </span><span class="java9">void </span><span class="java10">setValue</span><span class="java8">(</span><span class="java10">String value</span><span class="java8">)<br />
197 {</span><br />
198 <span class="offEDT">&#xA0; <span class="java4">this</span><span class="java10">.value = value;<br />
199 &#xA0; firePropertyChange</span><span class="java8">(</span><span class="java10">value</span><span class="java8">)</span><span class="java10">;</span></span><br />
200 <span class="java8">}</span>
201 <br />
202 <br />
203 <br />
204 <br />
205 <br />
206 &#xA0;</code></div>
207
208 <div class="clear"/>
209
210 <p>
211 Now what happens if the bean informs the <acronym title="Graphical user interface">GUI</acronym> about a value-change triggered by another thread? In <code>propertyChange()</code> we pass a runnable to the <acronym title="Event Dispatch Thread">EDT</acronym> via <code>SwingUtiltites.invokeLater()</code> that can safely alter the label.
212 </p>
213 <p>
214 Let's take a look at the colors once again: In <code>BeanImpl.java</code> there are only <span class="offEDT">red lines</span> - so we achieved a non freezing <acronym title="Graphical user interface">GUI</acronym>. <code>GUI.java</code> has <span class="onEDT">almost all lines in green</span>. Since we restrict changes to Swing components to these <span class="onEDT">green lines</span> we are honouring the Swing threading rule too.<br/>
215 But the <span class="offEDT">red lines </span> in <code>GUI.java</code> make things difficult: The programmer of this class always has to know which thread is stepping through what part of the code - without any visual help of thread-coloring. Any mistake reintroduces the problems mentioned above.
216 </p>
217 </subsection>
218 <subsection name="Swingworker">
219 <p>
220 SwingWorker is a utility class that aims to ease the efforts to write a non-freezing <acronym title="Graphical user interface">GUI</acronym>. Although not included in the standard Java distribution it is maintained by the Swing team and downloadable at <a href="http://www.theswingconnection.com">The Swing Connection</a>.
221 </p>
222 <p>
223 As you can see in the following example a SwingWorker removes some of the visual clutter seen in the previous section. To use it you have to subclass it, placing extensive calculations into method <code>construct()</code>. In <code>finished()</code> you can alter the label because this method is called on the <acronym title="Event Dispatch Thread">EDT</acronym>. This is similar to our previous solution but this time the threading is handled by the superclass:
224 </p>
225
226 <!--
227 public void actionPerformed(ActionEvent e)
228 {
229 label.setText("...");
230 new SwingWorker()
231 {
232 public Object construct()
233 {
234 return bean.getValue();
235 }
236
237 public void finished()
238 {
239 label.setText((String)getValue());
240 }
241 }).start();
242 }
243
244 public void propertyChange(final PropertyChangeEvent ev)
245 {
246 SwingUtilities.invokeLater(new Runnable()
247 {
248 public void run()
249 {
250 label.setText((String)ev.getNewValue());
251 }
252 });
253 }
254 -->
255 <div class="java left">
256 <h3 class="java">GUI.java</h3>
257 <code class="java"><span class="java4">public </span><span class="java9">void </span><span class="java10">actionPerformed</span><span class="java8">(</span><span class="java10">ActionEvent e</span><span class="java8">)<br />
258 {</span><br />
259 <span class="onEDT">&#xA0; <span class="java10">label.setText</span><span class="java8">(</span><span class="java5">&#34;...&#34;</span><span class="java8">)</span><span class="java10">;<br />
260 &#xA0; </span><span class="java4">new </span><span class="java10">SwingWorker</span><span class="java8">()<br />
261 &#xA0; {</span></span><br />
262 &#xA0;&#xA0;&#xA0; <span class="java4">public </span><span class="java10">Object construct</span><span class="java8">()<br />
263 &#xA0;&#xA0;&#xA0; {</span><br />
264 <span class="offEDT">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <span class="java4">return </span><span class="java10">bean.getValue</span><span class="java8">()</span><span class="java10">;</span></span><br />
265 &#xA0;&#xA0;&#xA0; <span class="java8">}<br />
266 <br />
267 &#xA0;&#xA0;&#xA0; </span><span class="java4">public </span><span class="java9">void </span><span class="java10">finished</span><span class="java8">()<br />
268 &#xA0;&#xA0;&#xA0; {</span><br />
269 <span class="onEDT">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <span class="java10">label.setText</span><span class="java8">((</span><span class="java10">String</span><span class="java8">)</span><span class="java10">getValue</span><span class="java8">())</span><span class="java10">;</span></span><br />
270 &#xA0;&#xA0;&#xA0; <span class="java8">}</span><br />
271 <span class="onEDT">&#xA0; <span class="java8">})</span><span class="java10">.start</span><span class="java8">()</span><span class="java10">;</span></span><br />
272 <span class="java8">}<br />
273 <br />
274 </span><span class="java4">public </span><span class="java9">void </span><span class="java10">propertyChange</span><span class="java8">(</span><span class="java4">final </span><span class="java10">PropertyChangeEvent ev</span><span class="java8">)<br />
275 {<br />
276 </span><span class="offEDT">&#xA0; <span class="java10">SwingUtilities.invokeLater</span><span class="java8">(</span><span class="java4">new </span><span class="java10">Runnable</span><span class="java8">()<br />
277 &#xA0; {<br /></span></span>
278 &#xA0;&#xA0;&#xA0; <span class="java4">public </span><span class="java9">void </span><span class="java10">run</span><span class="java8">()<br />
279 &#xA0;&#xA0;&#xA0; {</span><br />
280 <span class="onEDT">&#xA0;&#xA0;&#xA0;&#xA0;&#xA0; <span class="java10">label.setText</span><span class="java8">((</span><span class="java10">String</span><span class="java8">)</span><span class="java10">ev.getNewValue</span><span class="java8">())</span><span class="java10">;</span></span><br />
281 &#xA0;&#xA0;&#xA0; <span class="java8">}</span><br />
282 <span class="offEDT">&#xA0; <span class="java8">})</span><span class="java10">;</span></span><br />
283 <span class="java8">}</span></code></div>
284
285 <!--
286 public String getValue()
287 {
288 String value;
289 // extensive calculation
290 return value;
291 }
292
293 public void setValue(String value)
294 {
295 this.value = value;
296 firePropertyChange(value);
297 }
298 -->
299 <div class="java right">
300 <h3 class="java">BeanImpl.java</h3>
301 <code class="java"><span class="java4">public </span><span class="java10">String getValue</span><span class="java8">()<br />
302 {</span><br />
303 <span class="offEDT">&#xA0; <span class="java10">String value;<br />
304 &#xA0; </span><span class="java3">// extensive calculation<br />
305 &#xA0; </span><span class="java4">return </span><span class="java10">value;</span></span><br />
306 <span class="java8">}<br />
307 <br />
308 <br />
309 <br />
310 <br />
311 <br />
312 <br />
313 <br />
314 <br />
315 <br />
316 <br />
317 <br />
318 </span><span class="java4">public </span><span class="java9">void </span><span class="java10">setValue</span><span class="java8">(</span><span class="java10">String value</span><span class="java8">)<br />
319 {</span><br />
320 <span class="offEDT">&#xA0; <span class="java4">this</span><span class="java10">.value = value;<br />
321 &#xA0; firePropertyChange</span><span class="java8">(</span><span class="java10">value</span><span class="java8">)</span><span class="java10">;</span></span><br />
322 <span class="java8">}
323 <br />
324 <br />
325 <br />
326 <br />
327 <br />&#xA0;</span></code></div>
328
329 <div class="clear"/>
330
331 <p>
332 The SwingWorker offers no support for our notification problem so we stick to our previous solution in <code>propertyChange()</code>.
333 </p>
334 <p>
335 What about the colors?<br/>
336 The situation hasn't really improved. The indentation of code was minimized but we still have <span class="offEDT">red lines</span> in <code>GUI.java</code>. So the problem above isn't resolved yet, we're still seeking a better <a href="solution.html">solution</a>.
337 </p>
338 </subsection>
339 </section>
340 </body>
341 </document>

  ViewVC Help
Powered by ViewVC 1.1.26