UNPKG

epubjs

Version:

Render ePub documents in the browser, across many devices

151 lines (133 loc) 15.4 kB
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"><head><title>Multithreading in Swing</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="sect1" title="Multithreading in Swing"><div class="titlepage"><div><div><h1 class="title"><a id="learnjava3-CHP-16-SECT-5"/>Multithreading in Swing</h1></div></div></div><p><a id="idx10971" class="indexterm"/>An important compromise was made early in the design of Swing relating to speed, GUI consistency, and thread safety. To provide maximum performance and simplicity in the common case, Swing does not explicitly synchronize access to most Swing component methods. This means that most Swing components are, technically, not threadsafe for multithreaded applications. Now don’t panic: it’s not as bad as it sounds because there is a plan. All event processing in AWT/Swing is handled by a single system thread using a single system event queue. The queue serves two purposes. First, it eliminates thread safety issues by making all GUI modifications happen in a single thread. Second, the queue imposes a strict ordering of all activity in Swing. Because painting is handled in Swing using events, all screen updating is also ordered with respect to all event handling.</p><p>What this means for you is that multithreaded programs need to be careful about how they update Swing components after they are <span class="emphasis"><em>realized</em></span> (added to a visible container). If you make arbitrary modifications to Swing components from your own threads, you run the risk of malformed rendering on the screen and inconsistent behavior.</p><p>There are several conditions under which it is always safe to modify a Swing component. First, Swing components can be modified before they are realized. The term <span class="emphasis"><em>realized</em></span> originates from the days when the component would have created its peer object. It is the point when it is added to a visible container or when it is made visible in the case of a window. Most of our examples in this book set up GUI components in their <code class="literal">main()</code> method, add them to a <code class="literal">JFrame</code>, and then, as their final action, cause the <code class="literal">JFrame</code> to be displayed using <code class="literal">setVisible()</code>. This setup style is safe because components are not realized until the container is made visible. Actually, that last sentence is not entirely true. Technically, components can also be realized by the <code class="literal">JFrame() pack()</code> method. However, because no GUI is shown until the container is made visible, it is unlikely that any GUI activity can be mishandled.</p><p>Second, it’s safe to modify Swing components from code that is already running from the system event handler’s thread. Because all events are processed by the event queue, the methods of all Swing event listeners are normally invoked by the system event-handling thread. This means that event handler methods and, transitively, any methods called from those methods during the lifetime of that call, can freely modify Swing GUI components because they are already running in the system event-dispatching thread. If unsure of whether some bit of code will ever be called outside the normal event thread, you can use the static method <code class="literal">SwingUtilities.isEventDispatchThread()</code> to test the identity of the current thread. You can then perform your activity using the event-queue mechanism we’ll talk about next.</p><p>Finally, Swing components can be safely modified when the API documentation explicitly says that the method is threadsafe. Many important methods of Swing components are explicitly documented as threadsafe. These include the <code class="literal">JComponent repaint()</code> and <code class="literal">revalidate()</code> methods, many methods of Swing text components, and all listener add and remove methods.</p><p>If you can’t meet any of the requirements for thread safety listed previously, you can use a simple API to get the system event queue to perform arbitrary activities for you on the event-handling thread. This is accomplished using the <a id="I_indexterm16_id793484" class="indexterm"/><code class="literal">invokeAndWait()</code> or <a id="I_indexterm16_id793495" class="indexterm"/><code class="literal">invokeLater()</code> static methods of the <a id="I_indexterm16_id793506" class="indexterm"/><code class="literal">javax.swing.SwingUtilities</code> class:</p><div class="variablelist"><dl><dt><span class="term"><code class="literal">public static void invokeLater(Runnable doRun)</code></span></dt><dd><p>Use this method to ask Swing to execute the <code class="literal">run()</code> method of the specified <code class="literal">Runnable</code>.</p></dd><dt><span class="term"><code class="literal">public static void invokeAndWait(Runnable doRun)throwsInterruptedException,InvocationTargetException</code></span></dt><dd><p>This method is just like <code class="literal">invokeLater()</code> except that it waits until the <code class="literal">run()</code> method has completed before returning.</p></dd></dl></div><p>You can put any activities you want inside a <code class="literal">Runnable</code> object and cause the event dispatcher to perform them using these methods. Often you’ll use an inner class; for example:</p><a id="I_16_tt1001"/><pre class="programlisting"> <code class="n">SwingUtilities</code><code class="o">.</code><code class="na">invokeLater</code><code class="o">(</code> <code class="k">new</code> <code class="n">Runnable</code><code class="o">()</code> <code class="o">{</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">run</code><code class="o">()</code> <code class="o">{</code> <code class="n">MyComponent</code><code class="o">.</code><code class="na">setVisible</code><code class="o">(</code><code class="kc">false</code><code class="o">);</code> <code class="o">}</code> <code class="o">}</code> <code class="o">);</code></pre><p>Java 7 introduced the <a id="I_indexterm16_id793592" class="indexterm"/><code class="literal">SwingWorker</code> class to assist in situations where you have a background process that needs to update a Swing UI after the process is complete or incrementally as it’s running. In the former case, it’s a simple matter of subclassing <code class="literal">SwingWorker</code>, and putting your long-running code in <a id="I_indexterm16_id793613" class="indexterm"/><code class="literal">doInBackground()</code> and your UI update code in <a id="I_indexterm16_id793624" class="indexterm"/><code class="literal">done()</code>.</p><a id="I_programlisting16_id793634"/><pre class="programlisting"> <code class="kn">package</code> <code class="n">learning</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">java.awt.BorderLayout</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">java.awt.event.ActionEvent</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">java.awt.event.ActionListener</code><code class="o">;</code> <code class="kn">import</code> <code class="nn">javax.swing.*</code><code class="o">;</code> <code class="kd">public</code> <code class="kd">class</code> <code class="nc">MysteryOfTheUniverse</code> <code class="kd">extends</code> <code class="n">JFrame</code> <code class="o">{</code> <code class="n">JTextArea</code> <code class="n">textArea</code><code class="o">;</code> <code class="n">JButton</code> <code class="n">solveButton</code><code class="o">;</code> <code class="kd">public</code> <code class="nf">MysteryOfTheUniverse</code><code class="o">()</code> <code class="o">{</code> <code class="kd">super</code><code class="o">(</code><code class="s">"Mystery of the Universe Solver"</code><code class="o">);</code> <code class="n">setDefaultCloseOperation</code><code class="o">(</code> <code class="n">JFrame</code><code class="o">.</code><code class="na">EXIT_ON_CLOSE</code> <code class="o">);</code> <code class="n">setSize</code><code class="o">(</code><code class="mi">300</code><code class="o">,</code> <code class="mi">300</code><code class="o">);</code> <code class="n">textArea</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JTextArea</code><code class="o">();</code> <code class="n">solveButton</code> <code class="o">=</code> <code class="k">new</code> <code class="n">JButton</code><code class="o">(</code><code class="s">"Solve Mystery"</code><code class="o">);</code> <code class="n">solveButton</code><code class="o">.</code><code class="na">addActionListener</code><code class="o">(</code><code class="k">new</code> <code class="n">ActionListener</code><code class="o">()</code> <code class="o">{</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">actionPerformed</code><code class="o">(</code><code class="n">ActionEvent</code> <code class="n">ae</code><code class="o">)</code> <code class="o">{</code> <code class="n">solveButton</code><code class="o">.</code><code class="na">setEnabled</code><code class="o">(</code><code class="kc">false</code><code class="o">);</code> <code class="n">solveMysteryOfTheUniverse</code><code class="o">();</code> <code class="o">}</code> <code class="o">});</code> <code class="n">add</code><code class="o">(</code><code class="n">solveButton</code><code class="o">,</code> <code class="n">BorderLayout</code><code class="o">.</code><code class="na">NORTH</code><code class="o">);</code> <code class="n">add</code><code class="o">(</code><code class="k">new</code> <code class="n">JScrollPane</code><code class="o">(</code><code class="n">textArea</code><code class="o">));</code> <code class="n">add</code><code class="o">(</code><code class="k">new</code> <code class="n">JButton</code><code class="o">(</code><code class="s">"Click me! I'm not blocking."</code><code class="o">),</code> <code class="n">BorderLayout</code><code class="o">.</code><code class="na">SOUTH</code><code class="o">);</code> <code class="o">}</code> <code class="kd">public</code> <code class="kt">void</code> <code class="nf">solveMysteryOfTheUniverse</code><code class="o">()</code> <code class="o">{</code> <code class="o">(</code><code class="k">new</code> <code class="n">MysteryWorker</code><code class="o">()).</code><code class="na">execute</code><code class="o">();</code> <code class="o">}</code> <code class="kd">class</code> <code class="nc">MysteryWorker</code> <code class="kd">extends</code> <code class="n">SwingWorker</code><code class="o">&lt;</code><code class="n">String</code><code class="o">,</code> <code class="n">Object</code><code class="o">&gt;</code> <code class="o">{</code> <code class="nd">@Override</code> <code class="kd">public</code> <code class="n">String</code> <code class="nf">doInBackground</code><code class="o">()</code> <code class="o">{</code> <code class="c1">// Thinking for 4 seconds, but not blocking the UI</code> <code class="k">try</code> <code class="o">{</code> <code class="n">Thread</code><code class="o">.</code><code class="na">currentThread</code><code class="o">().</code><code class="na">sleep</code><code class="o">(</code><code class="mi">4000</code><code class="o">);</code> <code class="o">}</code> <code class="k">catch</code> <code class="o">(</code><code class="n">InterruptedException</code> <code class="n">ignore</code><code class="o">)</code> <code class="o">{}</code> <code class="n">solveButton</code><code class="o">.</code><code class="na">setEnabled</code><code class="o">(</code><code class="kc">true</code><code class="o">);</code> <code class="k">return</code> <code class="s">"Egg salad"</code><code class="o">;</code> <code class="o">}</code> <code class="nd">@Override</code> <code class="kd">protected</code> <code class="kt">void</code> <code class="nf">done</code><code class="o">()</code> <code class="o">{</code> <code class="k">try</code> <code class="o">{</code> <code class="n">textArea</code><code class="o">.</code><code class="na">setText</code><code class="o">(</code><code class="n">get</code><code class="o">());</code> <code class="o">}</code> <code class="k">catch</code> <code class="o">(</code><code class="n">Exception</code> <code class="n">ignore</code><code class="o">)</code> <code class="o">{}</code> <code class="o">}</code> <code class="o">}</code> <code class="kd">public</code> <code class="kd">static</code> <code class="kt">void</code> <code class="nf">main</code><code class="o">(</code><code class="n">String</code><code class="o">[]</code> <code class="n">args</code><code class="o">)</code> <code class="o">{</code> <code class="k">new</code> <code class="nf">MysteryOfTheUniverse</code><code class="o">().</code><code class="na">setVisible</code><code class="o">(</code><code class="kc">true</code><code class="o">);</code> <code class="o">}</code> <code class="o">}</code></pre><p>When you click the <span class="guibutton">Solve</span> button, the application spends four seconds solving the mystery of the universe. If we weren’t using <code class="literal">SwingWorker</code>, the event dispatch thread would block, making the <span class="guibutton">Click Me</span> button at the bottom of the screen unclickable. Thanks to <code class="literal">SwingWorker</code>, the UI remains usable during the time the background task is executing. Don’t trust us. Try it!</p><p><code class="literal">SwingWorker</code> can be used in more complex situations such as incremental updates of a progress bar. See <code class="literal">SwingWorker</code>’s JavaDoc introduction for an example of this usage.</p><p>You may find that you won’t have to use the event dispatcher or <code class="literal">SwingWorker</code> in simple GUI applications because most activity happens in response to user interface events where it is safe to modify components. However, consider these caveats when you create threads to perform long-running tasks such as loading data or communicating over the network.<a id="I_indexterm16_id793714" class="indexterm"/></p></div></body></html>