{"id":397,"date":"2021-02-05T17:07:31","date_gmt":"2021-02-05T17:07:31","guid":{"rendered":"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/?page_id=397"},"modified":"2021-02-05T21:25:02","modified_gmt":"2021-02-05T21:25:02","slug":"swing-threads","status":"publish","type":"page","link":"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/","title":{"rendered":"Swing &#038; Threads"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_85 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6a6d4811e3739\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6a6d4811e3739\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#The_Problem\" >The Problem<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#The_Single_Thread_Rule\" >The Single Thread Rule<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#The_GUI_main_Method\" >The GUI main Method<\/a><ul class='ez-toc-list-level-5' ><li class='ez-toc-heading-level-5'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#The_invokeLater_method\" >The invokeLater method<\/a><\/li><\/ul><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#Update_Swing_Only_from_the_EDT\" >Update Swing Only from the EDT<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#Illustrating_the_Problem\" >Illustrating the Problem<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#Fixing_the_Problem\" >Fixing the Problem<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#Avoid_Too_Much_Work_in_the_EDT\" >Avoid Too Much Work in the EDT<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#Illustrating_the_problem\" >Illustrating the problem<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#Whats_happening\" >What&#8217;s happening?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#Fixing_the_Problem-2\" >Fixing the Problem<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#Providing_Visual_Feedback\" >Providing Visual Feedback<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#Example_A_2-Phase_Responder\" >Example: A 2-Phase Responder<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#Using_a_Worker_Thread\" >Using a Worker Thread<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#Using_SwingWorker\" >Using SwingWorker<\/a><ul class='ez-toc-list-level-4' ><li class='ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#The_%E2%80%9CNew%E2%80%9D_SwingWorker\" >The &#8220;New&#8221; SwingWorker<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-4'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/course-topics\/swing-threads\/#An_Example\" >An Example<\/a><\/li><\/ul><\/li><\/ul><\/nav><\/div>\n\n<p class=\"wp-block-paragraph\">Swing presents some particular problems relating to multi-threaded programs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Since every Java GUI program is always multi-threaded, it&#8217;s important to understand what these problems are, and how to circumvent them.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"The_Problem\"><\/span>The Problem<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Swing was not designed to be fully thread-safe.&nbsp; Instead, it was designed in such a way that only code running in the event thread &#8212; that is, the thread in which events are delivered, or dispatched &#8212; is allowed to access Swing components.&nbsp;Code running in other threads which attempts to access Swing components is not guaranteed to work correctly, and has the potential of corrupting data in the Swing components..<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This was intentional, but it makes things more difficult for the programmer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This single-threaded, event thread-centric, design results in two distinct problems:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Trying to update Swing components from outside the event thread, and<\/li><li>Trying to do too much work in the event thread<\/li><\/ol>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"The_Single_Thread_Rule\"><\/span>The Single Thread Rule<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Swing event handling code runs on a special thread known as the&nbsp;<strong><em>Event Dispatch Thread<\/em><\/strong>. Most code that invokes Swing methods also runs on this thread. This is necessary because most Swing object methods are not &#8220;thread safe&#8221;: invoking them from multiple threads risks thread interference or memory consistency errors.&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The purpose of the Event Dispatch Thread is to&nbsp;<strong><em>serialize<\/em><\/strong>&nbsp;all GUI events, so that they cannot interfere with each other.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Some Swing component methods are labeled &#8220;thread safe&#8221; in the API specification; these can be safely invoked from any thread. However, these are in the minority.&nbsp; All other Swing component methods must be invoked from the event dispatch thread. Programs that ignore this rule may function correctly most of the time, but are subject to unpredictable errors that are difficult to reproduce.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The most useful of these thread-safe methods include:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code><strong>JTextComponent.setText<\/strong><\/code><\/li><li><code><strong>JTextArea.insert<\/strong><\/code><\/li><li><code><strong>JTextArea.append<\/strong><\/code><\/li><li><code><strong>JTextArea.replaceRange<\/strong><\/code><\/li><li><code><strong>JComponent.repaint<\/strong><\/code><\/li><li><code><strong>JComponent.revalidate<\/strong><\/code><\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Other Swing methods&nbsp;<strong><em>should be presumed not to be thread-safe<\/em><\/strong>.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"The_GUI_main_Method\"><\/span>The GUI main Method<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Of late, it has become much more important to require programmers to write their main entry points for a Swing GUI application in the following way:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage swingThreads;\n\nimport java.awt.EventQueue;\nimport javax.swing.JFrame;\n\n\/**\n * An example of how a typical main entry point should\n * be coded for a Swing GUI application\n *\/\npublic class SwingMain\n{\n  \/**\n   * Main entry point\n   *\/\n  public static void main(String&#x5B;] args)\n  {\n    EventQueue.invokeLater( new Runnable()\n      {\n        public void run()\n        {\n          JFrame frame = new JFrame(&quot;My GUI Application Frame&quot;);\n          frame.setBounds(200, 200, 500, 300);\n          frame.setVisible(true);\n        }\n      }\n    );\n  } \n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">One reason for this is the rapid increase in the number of truly multiprocessor machines, even at the low end of the PC market.&nbsp; These multiple processors turn multi-threading into true multi-processing, and enormously increase the possibility of race conditions.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">By writing the main entry point in this way, we can ensure that the changes to the relevant GUI objects are made exclusively in the Event Dispatch Thread, and so are appropriately serialized.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"The_invokeLater_method\"><\/span>The invokeLater method<span class=\"ez-toc-section-end\"><\/span><\/h5>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s what the javadocs say about the EventQueue.<strong>invokeLater<\/strong> method:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public static&nbsp;void&nbsp;invokeLater(<a href=\"https:\/\/docs.oracle.com\/javase\/7\/docs\/api\/java\/lang\/Runnable.html\">Runnable<\/a>&nbsp;runnable)<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Causes&nbsp;<code><strong>runnable<\/strong><\/code>&nbsp;to have its&nbsp;<code><strong>run<\/strong><\/code>&nbsp;method called in the&nbsp;<code><strong>dispatch thread<\/strong><\/code>&nbsp;of&nbsp;<code><strong>the system EventQueue<\/strong><\/code>. This will happen after all pending events are processed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Parameters:<\/strong><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code><strong>runnable<\/strong><\/code>&nbsp;&#8211; the&nbsp;<code><strong>Runnable<\/strong><\/code>&nbsp;whose&nbsp;<code>run<\/code>&nbsp;method should be executed asynchronously in the&nbsp;<strong><code>event dispatch thread<\/code>&nbsp;<\/strong>of&nbsp;<code><strong>the system EventQueue<\/strong><\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In other words, it prevents race conditions from occurring when executing such code within Swing programs.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Update_Swing_Only_from_the_EDT\"><\/span>Update Swing Only from the EDT<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The first problem to deal with is that one must update Swing GUI components from&nbsp;<strong><em>within<\/em><\/strong>, and not from outside the Event Dispatch Thread.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s some detail&#8230;<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Illustrating_the_Problem\"><\/span>Illustrating the Problem<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s a program that breaks the Swing single thread rule:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage potentialCorruption;\n\nimport java.awt.BorderLayout;\nimport java.awt.Color;\nimport java.awt.Container;\nimport java.awt.Font;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport javax.swing.JFrame;\nimport javax.swing.JButton;\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.JScrollPane;\nimport javax.swing.JTextArea;\nimport javax.swing.SwingConstants;\nimport javax.swing.WindowConstants;\n\n\/**\n * This class invokes multiple threads which (incorrectly) update the contents\n * of a Swing component from outside the event thread.\n *\/\n\npublic class PotentialCorruptor extends JFrame\n{\n  \/**\n   * Main entry point for Java application\n   *\/\n  public static void main(String&#x5B;] args)\n  {\n    PotentialCorruptor frame = new PotentialCorruptor();\n    frame.setVisible(true);\n  }\n  \n  \/**\n   * Construct the class\n   *\/\n  public PotentialCorruptor()\n  {\n    setTitle(&quot;Potential Corruptor Example&quot;);\n    setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE);\n    \n    Container panel = getContentPane();\n    panel.setLayout( new BorderLayout() );\n    m_buttonPanel = new ButtonPanel();\n    panel.add(m_buttonPanel, BorderLayout.CENTER);\n    \n    m_statusLabel.setFont( new Font( &quot;dialog&quot;, Font.BOLD, 14 ) );\n    panel.add(m_statusLabel, BorderLayout.SOUTH);\n    pack();\n  }\n  \n  \/**\n   * Button Panel\n   *\/\n  class ButtonPanel extends JPanel\n  {\n    ButtonPanel()\n    {\n      setBackground(Color.blue);\n      m_startButton.addActionListener( new ActionListener()\n        {\n          public void actionPerformed(ActionEvent ev)\n          {\n            setBackground(Color.red);\n            m_turnYellowButton.setEnabled(true);\n            m_textArea.setText(&quot;&quot;);\n            m_statusLabel.setText(&quot;Running...&quot;);\n            for (int i = 1; i &lt; TOTAL_THREADS; i++)\n            {\n              Thread thread = new CorruptorThread(&quot;Thread &quot; + i);\n              thread.start();\n            }\n          }\n        }\n      );\n      add(m_startButton);\n      \n      m_turnYellowButton.addActionListener( new ActionListener()\n        {\n          public void actionPerformed(ActionEvent ev)\n          {\n            ButtonPanel.this.setBackground(Color.yellow);\n          }\n        }\n      );\n      m_turnYellowButton.setEnabled(false);  \/\/ Disable for now\n      add(m_turnYellowButton);\n      \n      add( new JScrollPane(m_textArea) );\n    }\n    \n    \/**\n     * The thread to run\n     *\/\n    class CorruptorThread extends Thread\n    {\n      CorruptorThread(String name)\n      {\n        super(name);\n      }\n      \n      public void run()\n      {\n        int threadNumber = m_threadCount.incrementAndGet();\n        m_statusLabel.setText(&quot;Running (&quot; + threadNumber + &quot; threads)&quot;);\n        for (int i = 0; i &lt; 50; i++)\n        {\n          try\n          {\n            Thread.sleep(1);\n            update(&quot;&quot; + i);\n          }\n          catch (InterruptedException ie)\n          {\n            ie.printStackTrace();\n          }\n        }\n        \n        update(&quot;Thread Done&quot;);\n        threadNumber = m_threadCount.decrementAndGet();\n        m_statusLabel.setText(&quot;Running (&quot; + threadNumber + &quot; threads)&quot;);\n        if (threadNumber == 0)\n        {\n          m_statusLabel.setText(&quot;Done!&quot;);\n          m_buttonPanel.setBackground(Color.blue);\n          m_turnYellowButton.setEnabled(false);\n        }\n      }\n      \n      private void update(String text)\n      {\n        String temp = m_textArea.getText();\n        temp += &quot;\\n&quot; + getName() + &quot;: &quot; + text;\n        m_textArea.setText(temp);\n      }\n    }\n  }\n    \n  private ButtonPanel m_buttonPanel;\n  private JButton m_startButton = new JButton(&quot;Start (Turn Red)&quot;);\n  private JButton m_turnYellowButton = new JButton(&quot;Now Turn Yellow&quot;);\n  private JTextArea m_textArea = new JTextArea(10, 20);\n  private JLabel m_statusLabel = new JLabel(&quot;&quot;, SwingConstants.CENTER);\n  private static final int TOTAL_THREADS = 10;\n  private AtomicInteger m_threadCount = new AtomicInteger(0);\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Note that the program fires up 9 threads, each of which repeatedly sleeps, wakes up, updates the GUI (specifically a text area), and goes back to sleep again, exiting after a relatively large number of iterations.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p><strong><u>Note:<\/u>&nbsp;<\/strong>I have specifically avoided using the <code><strong>JTextArea<\/strong><\/code>&#8216;s <code><strong>append()<\/strong><\/code> method, because, unlike most Swing methods, it is thread-safe.&nbsp; Instead, I used a combination of&nbsp;<code><strong>getText()<\/strong><\/code>&nbsp;and&nbsp;<code><strong>setText()<\/strong><\/code>&nbsp;methods to exhibit the behavior.<\/p><\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">When I tried running this program, it produced something like this, after several clicks on the button:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"701\" src=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.28.23-PM-1024x701.png\" alt=\"\" class=\"wp-image-403\" srcset=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.28.23-PM-1024x701.png 1024w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.28.23-PM-300x205.png 300w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.28.23-PM-768x526.png 768w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.28.23-PM.png 1116w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n\n<div style=\"height:24px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Did you notice that the contents of the&nbsp;<code><strong>JTextArea<\/strong><\/code>&nbsp;occasionally get corrupted?&nbsp;I also noticed that the GUI layout changed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Even worse, you might experience more serious problems.&nbsp; I encountered at least one occasion when the entire GUI locked up, and became totally unresponsive.&nbsp; Probably, there was some internal corruption taking place.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Fixing_the_Problem\"><\/span>Fixing the Problem<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Because you very often need to be able to update Swing components from outside the event thread, Swing provides two useful methods which allow you to cause your code to run in the event loop.&nbsp; They are static methods in the&nbsp;<code><strong>javax.swing.<\/strong><\/code><code><strong>SwingUtilities<\/strong><\/code>&nbsp;class (also in&nbsp;<code><strong>java.awt.EventQueue<\/strong><\/code>):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">public static void <strong>invokeLater<\/strong>(Runnable&nbsp;doRun)<\/pre>\n\n\n\n<pre class=\"wp-block-preformatted\">public static void <strong>invokeAndWait<\/strong>(Runnable&nbsp;doRun)\n                          throws InterruptedException,\n                               InvocationTargetException<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">In each case, you must provide an instance of a class which implements the&nbsp;<code><strong>Runnable<\/strong><\/code>&nbsp;interface.&nbsp; Each method will cause the&nbsp;<code><strong>run()<\/strong><\/code>&nbsp;method of this class to be invoked asynchronously in the event dispatching thread.&nbsp; It will be processed in turn, based on what other requests are pending in that thread.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An&nbsp;<code><strong>invokeLater()<\/strong><\/code>&nbsp;call will simply cause the scheduling of the&nbsp;<code><strong>Runnable<\/strong><\/code>&nbsp;class code.&nbsp;&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">An&nbsp;<code><strong>invokeAndWait()<\/strong><\/code>&nbsp;call will will block the thread until all pending AWT events have been processed and (then)&nbsp;<em>doRun.run()<\/em>&nbsp;returns.&nbsp; <\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>For obvious reasons, <strong>invokeAndWait()<\/strong> should&nbsp;<strong><em>not<\/em><\/strong>&nbsp;be called from the event dispatch thread.<\/p><\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s the example, fixed, using these techniques:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; highlight: [11,92,93,94,95,96,97,98,99,100,101]; title: ; quick-code: false; notranslate\" title=\"\">\npackage notPotentialCorruption;\n\nimport java.awt.Color;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport javax.swing.JFrame;\nimport javax.swing.JButton;\nimport javax.swing.JPanel;\nimport javax.swing.JScrollPane;\nimport javax.swing.JTextArea;\nimport javax.swing.SwingUtilities;\n\n\/**\n * This class invokes multiple threads which (incorrectly) update the contents\n * of a Swing component from outside the event thread.\n *\/\n\npublic class NotPotentialCorruptor extends JFrame\n{\n   \/\/Construct the frame\n   public NotPotentialCorruptor()\n   {\n      setTitle(&quot;Not Potential Corruptor Example&quot;);\n      getContentPane().add( new ButtonPanel() );\n      pack();\n   }\n\n   class ButtonPanel extends JPanel implements ActionListener\n   {\n      ButtonPanel()\n      {\n         setBackground(Color.blue);\n         m_clickMeButton.addActionListener(this);\n         add(m_clickMeButton);\n\n         m_nowClickMeButton.addActionListener( new ActionListener()\n         {\n            public void actionPerformed(ActionEvent ev)\n            {\n               ButtonPanel.this.setBackground(Color.yellow);\n            }\n         }\n         );\n         m_nowClickMeButton.setEnabled(false);  \/\/ Disable for now\n         add(m_nowClickMeButton);\n\n         add( new JScrollPane(m_statusArea) );\n      }\n\n      public void actionPerformed(ActionEvent ev)\n      {\n         setBackground(Color.red);\n         m_nowClickMeButton.setEnabled(true);\n         for (int i = 1; i &lt; 10; i++)\n         {\n            Thread thread = new CorruptorThread(&quot;Thread &quot; + i);\n            thread.start();\n         }\n      }\n\n      private JButton m_clickMeButton = new JButton(&quot;Click me!&quot;);\n      private JButton m_nowClickMeButton = new JButton(&quot;Now try to click me!&quot;);\n      private JTextArea m_statusArea = new JTextArea(10, 20);\n\n      class CorruptorThread extends Thread\n      {\n         CorruptorThread(String name)\n         {\n            super(name);\n         }\n\n         public void run()\n         {\n            for (int i = 0; i &lt; 100; i++)\n            {\n               try\n               {\n                  Thread.sleep(1);\n                  update(&quot;&quot; + i);\n               }\n               catch (InterruptedException ie)\n               {\n                  ie.printStackTrace();\n               }\n            }\n\n            update(&quot;Done&quot;);\n         }\n\n         private void update(final String text)\n         {\n            Runnable runnable = new Runnable()\n            {\n              public void run()\n              {\n                 String temp = m_statusArea.getText();\n                 temp += &quot;\\n&quot; + getName() + &quot;: &quot; + text;\n                 m_statusArea.setText(temp);\n              }\n            };\n            SwingUtilities.invokeLater(runnable);\n         }\n      }\n   }\n\n   public static void main(String&#x5B;] args)\n   {\n      NotPotentialCorruptor frame = new NotPotentialCorruptor();\n      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\n      frame.setVisible(true);\n   }\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Note that the code inside the update method has been enclosed within the <strong>run()<\/strong> method of an inner class which implements the <strong>Runnable<\/strong> interface.&nbsp; The inner class is then passed into a call to the <strong>invokeLater()<\/strong> method.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This produces the following, which behaves much better. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"396\" src=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.42.00-PM-1024x396.png\" alt=\"\" class=\"wp-image-404\" srcset=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.42.00-PM-1024x396.png 1024w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.42.00-PM-300x116.png 300w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.42.00-PM-768x297.png 768w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.42.00-PM.png 1086w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The contents of the text area do not get corrupted, and the GUI layout remains stable. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Note that the threads can take a while, so be patient!<\/p>\n\n\n\n<div style=\"height:100px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Avoid_Too_Much_Work_in_the_EDT\"><\/span>Avoid Too Much Work in the EDT<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The second problem to deal with is that one must&nbsp;<em><strong>avoid doing too much work from within<\/strong><\/em>&nbsp;the Event Dispatch Thread.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Illustrating_the_problem\"><\/span>Illustrating the problem<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Consider the following code:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage hangThread;\n\nimport java.awt.BorderLayout;\nimport java.awt.Color;\nimport java.awt.Container;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport javax.swing.JButton;\nimport javax.swing.JFrame;\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.SwingConstants;\nimport javax.swing.SwingUtilities;\n\n\/**\n * This is a frame which illustrates the problems associated with trying to\n * do large amounts of work from within the Event Dispatch Thread.\n *\/\n\npublic class HangThreadExample extends JFrame\n{\n  public HangThreadExample()\n  {\n    setTitle(&quot;Hang Thread Example&quot;);\n    setSize(200, 200);\n    Container contentPane = getContentPane();\n    contentPane.setLayout(new BorderLayout());\n    contentPane.add( new ButtonPanel(), BorderLayout.CENTER );\n    contentPane.add(m_progressLabel, BorderLayout.SOUTH);\n  }\n  \n  private void doWork()\n  {\n    try\n    {\n      Thread.sleep(10000); \/\/ represents a long operation of some kind.\n    }\n    catch (InterruptedException ie)\n    {\n      ie.printStackTrace();\n    }\n  }\n  \n  private void setProgress(final String text)\n  {\n    m_progressLabel.setText(text);\n  }\n  \n  class ButtonPanel extends JPanel implements ActionListener\n  {\n    ButtonPanel()\n    {\n      setBackground(Color.blue);\n      m_clickMeButton.addActionListener(this);\n      add(m_clickMeButton);\n      \n      m_nowClickMeButton.addActionListener( new ActionListener()\n      {\n        public void actionPerformed(ActionEvent ev)\n        {\n          ButtonPanel.this.setBackground(Color.yellow);\n        }\n      }\n      );\n      m_nowClickMeButton.setEnabled(false);  \/\/ Disable for now\n      add(m_nowClickMeButton);\n    }\n    \n    public void actionPerformed(ActionEvent ev)\n    {\n      m_clickMeButton.setEnabled(false);\n      Color oldColor = getBackground(); \/\/ Save color\n      setBackground(Color.red);\n      m_nowClickMeButton.setEnabled(true);\n      \n      setProgress(&quot;Working...&quot;);\n      doWork();\n      setProgress(&quot;Done&quot;);\n      \n      m_clickMeButton.setEnabled(true);\n    }\n  }\n  \n  public static void main(String&#x5B;] args)\n  {\n    HangThreadExample frame = new HangThreadExample();\n    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\n    frame.setVisible(true);\n  }\n  \n  private JButton m_clickMeButton = new JButton(&quot;Click me!&quot;);\n  private JButton m_nowClickMeButton = new JButton(&quot;Now try to click me!&quot;);\n  private JLabel m_progressLabel = new JLabel(&quot; &quot;, SwingConstants.CENTER);\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">It simulates doing a lot of time-consuming work from the AWT event dispatch thread.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Note the ButtonPanel&#8217;s <strong>actionPerformed<\/strong> method, which is invoked (from the AWT event dispatch thread) when you click on the &#8220;Click me!&#8221; button.&nbsp; It&nbsp; does the following:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Sets the background color of the ButtonPanel to red<\/li><li>Enables the &#8220;Now try to click me!&#8221; button.<\/li><li>Calls the <strong>HangThreadExample<\/strong> class&#8217;s <strong>doWork()<\/strong> method<\/li><li>After returning from the <strong>doWork()<\/strong> method, it sets the background back to its original color, and disables the &#8220;Now try to click me!&#8221; button.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Here is a sequence of image captures from running this program:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"418\" height=\"414\" src=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.54.02-PM.png\" alt=\"\" class=\"wp-image-408\" srcset=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.54.02-PM.png 418w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.54.02-PM-300x297.png 300w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.54.02-PM-150x150.png 150w\" sizes=\"auto, (max-width: 418px) 100vw, 418px\" \/><figcaption>The initial state of the program<\/figcaption><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"418\" height=\"414\" src=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.54.21-PM.png\" alt=\"\" class=\"wp-image-409\" srcset=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.54.21-PM.png 418w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.54.21-PM-300x297.png 300w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.54.21-PM-150x150.png 150w\" sizes=\"auto, (max-width: 418px) 100vw, 418px\" \/><figcaption>After clicking on &#8220;Click me!&#8221;, the GUI hangs for some time.<\/figcaption><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"412\" height=\"410\" src=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.54.48-PM.png\" alt=\"\" class=\"wp-image-410\" srcset=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.54.48-PM.png 412w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.54.48-PM-300x300.png 300w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.54.48-PM-150x150.png 150w\" sizes=\"auto, (max-width: 412px) 100vw, 412px\" \/><figcaption>Finally, the GUI returns&#8230;<\/figcaption><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"418\" height=\"410\" src=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.55.09-PM.png\" alt=\"\" class=\"wp-image-411\" srcset=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.55.09-PM.png 418w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-2.55.09-PM-300x294.png 300w\" sizes=\"auto, (max-width: 418px) 100vw, 418px\" \/><figcaption>This is what you get after clicking on the &#8220;Now try to click me!&#8221; button.<\/figcaption><\/figure><\/div>\n\n\n\n<div style=\"height:13px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">If I were to click on the &#8220;Click me!&#8221; button again, it would again hang for a while.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Whats_happening\"><\/span>What&#8217;s happening?<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Did you notice that:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>The &#8220;Click me!&#8221; button remains depressed, and doesn&#8217;t &#8220;spring back&#8221; until after a long delay?<\/li><li>The background color similarly did not change to red until after the same delay?<\/li><li>The &#8220;Now try to click me!&#8221; button is not enabled, again, until after the same delay?<\/li><li>The whole GUI freezes for a long time?<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">All of this is because the&nbsp;<code><strong>doWork()<\/strong><\/code>&nbsp;method was invoked from, and therefore runs in the context of, the Event Dispatch Thread.&nbsp; All of the requests for changes to the GUI that the&nbsp;<code><strong>actionPerformed()<\/strong><\/code>&nbsp;method requested were entered in the queue for the event dispatch thread. However, since events are dispatched serially, one at a time, and because the&nbsp;<code><strong>doWork()<\/strong><\/code>&nbsp;method was hogging the event dispatch thread, none of the GUI requests were acted upon until the work had been completed, by which time the&nbsp;<code><strong>actionPerformed()<\/strong><\/code>&nbsp;method had undone its requests (actually, requested additional changes to the GUI which reversed the original requests.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The above program is a typical example of what happens when a listener for an event tries to do too much work in direct response to receiving the listener callback for its event.&nbsp; Doing this kind of thing can result in GUIs which respond poorly to user interaction.&nbsp; <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We&#8217;ve probably all experienced GUI programs which exhibit such poor behavior &#8212; but we can do better!<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Fixing_the_Problem-2\"><\/span>Fixing the Problem<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">The solution to this problem is to cause long-running work to be done in a separate thread.&nbsp;&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here is a version of the above program that solves the problem:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage noHangThread;\n\nimport java.awt.BorderLayout;\nimport java.awt.Color;\nimport java.awt.Container;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport javax.swing.JFrame;\nimport javax.swing.JButton;\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.SwingConstants;\nimport javax.swing.SwingUtilities;\n\n\/**\n * This is a frame which solves the problems associated with trying to\n * do large amounts of work from within the Event Dispatch Thread.\n *\/\n\npublic class NoHangThreadExample extends JFrame\n{\n  \/\/Construct the frame\n  public NoHangThreadExample()\n  {\n    setTitle(&quot;No Hang Thread Example&quot;);\n    setSize(200, 200);\n    Container contentPane = getContentPane();\n    contentPane.setLayout(new BorderLayout());\n    contentPane.add( new ButtonPanel(), BorderLayout.CENTER );\n    contentPane.add(m_progressLabel, BorderLayout.SOUTH);\n  }\n  \n  private void doWork()\n  {\n    setProgress(false, &quot;Working...&quot;);\n    try\n    {\n      Thread.sleep(10000); \/\/ represents a long operation of some kind.\n    }\n    catch (InterruptedException ie)\n    {\n      ie.printStackTrace();\n    }\n    setProgress(true, &quot;Done&quot;);\n  }\n  \n  private void setProgress(final boolean enableButton, final String text)\n  {\n    SwingUtilities.invokeLater( new Runnable()\n    {\n      public void run()\n      {\n        m_clickMeButton.setEnabled(enableButton);\n        m_progressLabel.setText(text);\n      }\n    }\n    );\n  }\n  \n  class ButtonPanel extends JPanel implements ActionListener\n  {\n    ButtonPanel()\n    {\n      setBackground(Color.blue);\n      m_clickMeButton.addActionListener(this);\n      add(m_clickMeButton);\n      \n      m_nowClickMeButton.addActionListener( new ActionListener()\n      {\n        public void actionPerformed(ActionEvent ev)\n        {\n          ButtonPanel.this.setBackground(Color.yellow);\n        }\n      }\n      );\n      m_nowClickMeButton.setEnabled(false);  \/\/ Disable for now\n      add(m_nowClickMeButton);\n    }\n    \n    public void actionPerformed(ActionEvent ev)\n    {\n      setBackground(Color.red);\n      m_nowClickMeButton.setEnabled(true);\n      Thread thread = new Thread()\n      {\n        public void run()\n        {\n          doWork();\n        }\n      };\n      thread.start();\n    }\n  }\n  \n  public static void main(String&#x5B;] args)\n  {\n    NoHangThreadExample frame = new NoHangThreadExample();\n    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\n    frame.setVisible(true);\n  }\n  \n  private JButton m_clickMeButton = new JButton(&quot;Click me!&quot;);\n  private JButton m_nowClickMeButton = new JButton(&quot;Now try to click me!&quot;);\n  private JLabel m_progressLabel = new JLabel(&quot; &quot;, SwingConstants.CENTER);\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Note that the only change is to invoke <strong>doWork()<\/strong> from a separate thread.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The following images show the improved behavior:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"410\" height=\"416\" src=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.11.46-PM.png\" alt=\"\" class=\"wp-image-414\" srcset=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.11.46-PM.png 410w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.11.46-PM-296x300.png 296w\" sizes=\"auto, (max-width: 410px) 100vw, 410px\" \/><figcaption>The initial state of the program<\/figcaption><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"408\" height=\"410\" src=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.12.08-PM.png\" alt=\"\" class=\"wp-image-415\" srcset=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.12.08-PM.png 408w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.12.08-PM-300x300.png 300w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.12.08-PM-150x150.png 150w\" sizes=\"auto, (max-width: 408px) 100vw, 408px\" \/><figcaption>After clicking &#8220;Click me!&#8221;<\/figcaption><\/figure><\/div>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"412\" height=\"410\" src=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.12.27-PM.png\" alt=\"\" class=\"wp-image-416\" srcset=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.12.27-PM.png 412w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.12.27-PM-300x300.png 300w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.12.27-PM-150x150.png 150w\" sizes=\"auto, (max-width: 412px) 100vw, 412px\" \/><figcaption>After the work has been done&#8230;<\/figcaption><\/figure><\/div>\n\n\n\n<div style=\"height:18px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Did you notice that, now:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>The &#8220;Click me!&#8221; button &#8220;springs back&#8221; immediately?<\/li><li>The background color changes to red immediately?<\/li><li>The &#8220;Now try to click me!&#8221; button is now enabled immediately?<\/li><li>The whole GUI does not freeze?<\/li><li>That the state of the &#8220;work&#8221; is correctly indicated in the bottom bar?<\/li><\/ul>\n\n\n\n<div style=\"height:54px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Providing_Visual_Feedback\"><\/span>Providing Visual Feedback<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">As you have already seen, it is usually very important to provide some kind of feedback &#8212; usually visual &#8212; to ensure that the user understands that something is happening, and so the user can tell when background work has completed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There are a number of ways of accomplishing this.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Example_A_2-Phase_Responder\"><\/span>Example: A 2-Phase Responder<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s a simple example of how one might provide visual feedback from time-consuming work processing in a background thread:&nbsp; A <em>&#8220;2-Phase Responder&#8221;<\/em>.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage multiResponse;\n\n\/**\n * This is an interface for a two-phase progress responder.\n *\/\npublic interface TwoPhaseResponder\n{\n  \/**\n   * Called when the work has started\n   *\/\n  public void started();\n  \n  \/**\n   * Called when the first phase of the work is complete\n   *\/\n  public void phase1Complete();\n  \n  \/**\n   * Called when the second phase of the work is complete\n   *\/\n  public void phase2Complete();\n  \n  \/**\n   * Called when all the work is complete\n   *\/\n  public void done();\n}\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage multiResponse;\n\n\/**\n * This is a two-phase worker thread\n *\/\npublic class TwoPhaseWorker extends Thread\n{\n  public TwoPhaseWorker(TwoPhaseResponder responder)\n  {\n    m_responder = responder;\n  }\n  \n  public void run()\n  {\n    m_responder.started();\n    try\n    {\n      Thread.sleep(5000); \/\/ represents a long operation of some kind.\n      m_responder.phase1Complete();\n      \n      Thread.sleep(5000); \/\/ represents another long operation of some kind.\n      m_responder.phase2Complete();\n      \n      Thread.sleep(500); \/\/ Give the user a chance to see the second phase completed message\n    }\n    catch (InterruptedException ie)\n    {\n      ie.printStackTrace();\n    }\n    m_responder.done();\n  }\n  \n  private TwoPhaseResponder m_responder;\n}\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage multiResponse;\n\nimport java.awt.BorderLayout;\nimport java.awt.Color;\nimport java.awt.Container;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.lang.reflect.InvocationTargetException;\nimport javax.swing.JFrame;\nimport javax.swing.JButton;\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.SwingUtilities;\n\n\/**\n * This is a frame which shows how we can provide visual responses from each of\n * several phases of time-consuming work in a background worker thread.\n *\/\npublic class TwoPhaseResponderExample extends JFrame\n{\n  public TwoPhaseResponderExample()\n  {\n    setTitle(&quot;Two-phase Responder Example&quot;);\n    setSize(200, 200);\n    Container contentPane = getContentPane();\n    contentPane.setLayout(new BorderLayout());\n    contentPane.add( new ButtonPanel(), BorderLayout.CENTER );\n    contentPane.add(m_progressLabel, BorderLayout.SOUTH);\n  }\n  \n  class ButtonPanel extends JPanel implements ActionListener, TwoPhaseResponder\n  {\n    ButtonPanel()\n    {\n      setBackground(Color.blue);\n      m_clickMeButton.addActionListener(this);\n      add(m_clickMeButton);\n      \n      m_nowClickMeButton.addActionListener( new ActionListener()\n      {\n        public void actionPerformed(ActionEvent ev)\n        {\n          ButtonPanel.this.setBackground(Color.yellow);\n        }\n      }\n      );\n      m_nowClickMeButton.setEnabled(false);  \/\/ Disable for now\n      add(m_nowClickMeButton);\n    }\n    \n    public void actionPerformed(ActionEvent ev)\n    {\n      setBackground(Color.red);\n      m_nowClickMeButton.setEnabled(true);\n      m_progressLabel.setText(&quot;Background work in progress&quot;);\n      TwoPhaseWorker thread = new TwoPhaseWorker(this);\n      thread.start();\n    }\n    \n    public void started()\n    {\n      setStatus(&quot;Started work...&quot;);\n    }\n    \n    public void phase1Complete()\n    {\n      setStatus(&quot;Phase 1 complete&quot;);\n    }\n    \n    public void phase2Complete()\n    {\n      setStatus(&quot;Phase 2 complete&quot;);\n    }\n    \n    public void done()\n    {\n      setStatus(&quot;Work Completed&quot;);\n    }\n    \n    private void setStatus(final String text)\n    {\n      SwingUtilities.invokeLater( new Runnable()\n        {\n          public void run()\n          {\n            m_progressLabel.setText(text);\n          }\n        }\n      );\n    }\n  }\n  \n  public static void main(String&#x5B;] args)\n  {\n    TwoPhaseResponderExample frame = new TwoPhaseResponderExample();\n    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\n    frame.setVisible(true);\n  }\n  \n  private JButton m_clickMeButton = new JButton(&quot;Click me!&quot;);\n  private JButton m_nowClickMeButton = new JButton(&quot;Now try to click me!&quot;);\n  private JLabel m_progressLabel = new JLabel(&quot; &quot;, SwingUtilities.CENTER);\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">After you&#8217;ve brought up the JFrame, click on the &#8220;Click me!&#8221; button, and see what actually happens!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The resulting JFrame should contain a JLabel field that is updated at appropriate places in the program, to indicate when work has started, when phase 1 is complete, when phase 2 is complete, and when all work has completed.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Here is what the program produces:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"416\" height=\"414\" src=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.29.48-PM.png\" alt=\"\" class=\"wp-image-420\" srcset=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.29.48-PM.png 416w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.29.48-PM-300x300.png 300w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-3.29.48-PM-150x150.png 150w\" sizes=\"auto, (max-width: 416px) 100vw, 416px\" \/><\/figure><\/div>\n\n\n\n<div style=\"height:26px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">The message in the bottom bar goes from blank, and when the &#8220;Click me! button is clicked, to &#8220;Started work&#8221;, to &#8220;Phase 1 complete&#8221;, to &#8220;Phase 2 complete&#8221; to &#8220;Work Completed&#8221;.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Using_a_Worker_Thread\"><\/span>Using a Worker Thread<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">If we want to separate out the work from the way it is invoked (<em>&#8220;separation of form vs. function&#8221;<\/em>), we can create ourselves a&nbsp;<strong><em>worker thread<\/em><\/strong>&nbsp;which can perform the necessary long-running work:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage workerThread;\n\n\/**\n * This is an interface for a status responder.\n *\/\npublic interface StatusResponder\n{\n  \/**\n   * Called when the work has started\n   *\/\n  public void started();\n  \n  \/**\n   * Called when all the work is complete\n   *\/\n  public void done();\n}\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage workerThread;\n\n\/**\n * This class is a worker thread which can be used to perform \n * time-consuming work outside of the event dispatch thread.\n *\/\n\npublic class WorkerThread extends Thread\n{\n  public WorkerThread(StatusResponder responder)\n  {\n    m_responder = responder;\n  }\n  \n  \/**\n   * The run method for the worker thread, \n   * where the work gets done.\n   *\/\n  public void run()\n  {\n    m_responder.started();\n    try\n    {\n      Thread.sleep(10000); \/\/ represents a long operation of some kind.\n    }\n    catch (InterruptedException ie)\n    {\n      ie.printStackTrace();\n    }\n    m_responder.done();\n  }\n  \n  private StatusResponder m_responder;\n}\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; highlight: [58]; title: ; notranslate\" title=\"\">\npackage workerThread;\n\nimport java.awt.BorderLayout;\nimport java.awt.Color;\nimport java.awt.Container;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport javax.swing.JFrame;\nimport javax.swing.JButton;\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.SwingConstants;\nimport javax.swing.SwingUtilities;\n\n\/**\n * This is a frame which solves the problems associated with trying to\n * do large amounts of work from within the Event Dispatch Thread.\n * It uses a separate WorkerThread class.\n *\/\n\npublic class WorkerThreadExample extends JFrame\n{\n  \/\/Construct the frame\n  public WorkerThreadExample()\n  {\n    setTitle(&quot;Worker Thread Example&quot;);\n    setSize(200, 200);\n    Container contentPane = getContentPane();\n    contentPane.setLayout(new BorderLayout());\n    contentPane.add( new ButtonPanel(), BorderLayout.CENTER );\n    contentPane.add(m_progressLabel, BorderLayout.SOUTH);\n  }\n  \n  class ButtonPanel extends JPanel implements ActionListener\n  {\n    ButtonPanel()\n    {\n      setBackground(Color.blue);\n      m_clickMeButton.addActionListener(this);\n      add(m_clickMeButton);\n      \n      m_nowClickMeButton.addActionListener( new ActionListener()\n        {\n          public void actionPerformed(ActionEvent ev)\n          {\n            ButtonPanel.this.setBackground(Color.yellow);\n          }\n        }\n      );\n      m_nowClickMeButton.setEnabled(false);  \/\/ Disable for now\n      add(m_nowClickMeButton);\n    }\n    \n    public void actionPerformed(ActionEvent ev)\n    {\n      setBackground(Color.red);\n      m_nowClickMeButton.setEnabled(true);\n      new WorkerThread( new Responder() ).start();\n    }\n  }\n  \n  public static void main(String&#x5B;] args)\n  {\n    WorkerThreadExample frame = new WorkerThreadExample();\n    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\n    frame.setVisible(true);\n  }\n  \n  \/**\n   * Inner responder class\n   *\/\n  class Responder implements StatusResponder\n  {\n    public void started()\n    {\n      setStatus(false, &quot;Started work...&quot;);\n    }\n    \n    public void done()\n    {\n      setStatus(true, &quot;Done!&quot;);\n    }\n    \n    private void setStatus(final boolean enable, final String text)\n    {\n      SwingUtilities.invokeLater( new Runnable()\n        {\n          public void run()\n          {\n            m_progressLabel.setText(text);\n            m_clickMeButton.setEnabled(enable);\n          }\n        }\n      );\n    }\n  }\n  \n  private JButton m_clickMeButton = new JButton(&quot;Click me!&quot;);\n  private JButton m_nowClickMeButton = new JButton(&quot;Now try to click me!&quot;);\n  private JLabel m_progressLabel = new JLabel(&quot; &quot;, SwingConstants.CENTER);\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">The only change we made was to move the work out into the separate <code><strong>WorkerThread<\/strong><\/code>&#8216;s <code><strong>run()<\/strong><\/code> method.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Note that we have provided a&nbsp;<code><strong>StatusResponder<\/strong><\/code>&nbsp;to provide some user feedback.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The results of this program are very similar to earlier versions; we are just using a WorkerThread to do the time-consuming work.<\/p>\n\n\n\n<div style=\"height:50px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"Using_SwingWorker\"><\/span>Using SwingWorker<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Some Sun Java folks came up with a class that they called&nbsp;<code><strong>SwingWorker<\/strong><\/code>, to illustrate good practice using a worker thread model.In this section, we&#8217;ll show some examples of the use of&nbsp;<code><strong>SwingWorker<\/strong><\/code>.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>Note that a version of the\u00a0<code><strong>SwingWorker<\/strong><\/code>\u00a0class was included in Java 6.0 (<code><strong>javax.swing.SwingWorker<\/strong><\/code>); it was not the same as the original <code><strong>SwingWorker<\/strong><\/code>.\u00a0\u00a0Before 6.0, you had to download it separately.<\/p><\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">They introduced a useful class called <strong>SwingWorker<\/strong>, which provides some very useful features. <a href=\"https:\/\/docs.oracle.com\/javase\/tutorial\/uiswing\/concurrency\/worker.html\" target=\"_blank\" rel=\"noreferrer noopener\">Here<\/a>&#8216;s where to find more information about <strong>SwingWorker<\/strong>.<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li><code><strong>SwingWorker<\/strong><\/code>&nbsp;is an abstract class which you can extend in your own subclass to add useful functionality.<\/li><li>It allows you to compute a value in a new thread.<\/li><li>Your subclass will override the construct() method, within which the value will be computed (in the new thread)<\/li><li>Your subclass can override the finished() method, which is automatically invoked in the event thread at the end of the work performed in computing the value.<\/li><li>The work performed by a SwingWorker can be interrupted<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">The old version of the\u00a0<code><strong>SwingWorker<\/strong><\/code>\u00a0class is not part of the Java distribution (and will not be), but it can be downloaded from the above web pages.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"The_%E2%80%9CNew%E2%80%9D_SwingWorker\"><\/span>The &#8220;New&#8221; SwingWorker<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">The original&nbsp;<code><strong>SwingWorker<\/strong><\/code>&nbsp;class used not to be part of the Java distribution, but a new version of it is now included in Java 6.0 (<code><strong><a href=\"http:\/\/java.sun.com\/javase\/6\/docs\/api\/javax\/swing\/SwingWorker.html\" target=\"_blank\" rel=\"noreferrer noopener\">javax.swing.SwingWorker<\/a><\/strong><\/code>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><code><strong>SwingWorker<\/strong><\/code>\u00a0provides a number of communication and control features:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>The\u00a0<code><strong>SwingWorker<\/strong><\/code>\u00a0subclass can define a method,\u00a0<code><strong>done()<\/strong><\/code>, which is automatically invoked on the event dispatch thread when the background task is finished.<\/li><li><code><strong>SwingWorker<\/strong><\/code>\u00a0implements\u00a0<code><strong>java.util.concurrent.Future<\/strong><\/code>. This interface allows the background task to provide a return value to the other thread. Other methods in this interface allow cancellation of the background task and discovering whether the background task has finished or been cancelled.<\/li><li>The background task can provide intermediate results by invoking\u00a0<code><strong>SwingWorker.publish()<\/strong><\/code>, causing <strong><code>SwingWorker.process()<\/code> <\/strong>to be invoked from the event dispatch thread.<\/li><li>The background task can define bound properties. Changes to these properties trigger events, causing event-handling methods to be invoked on the event dispatch thread.<\/li><\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"An_Example\"><\/span>An Example<span class=\"ez-toc-section-end\"><\/span><\/h4>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s an example of the use of the &#8220;new&#8221; (i.e. Java 6.0)\u00a0<code><strong>SwingWorker<\/strong><\/code>\u00a0class:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: java; auto-links: false; title: ; quick-code: false; notranslate\" title=\"\">\npackage swingWorker;\n\nimport java.awt.BorderLayout;\nimport java.awt.Color;\nimport java.awt.Container;\nimport java.awt.EventQueue;\nimport java.awt.event.ActionEvent;\nimport java.awt.event.ActionListener;\nimport java.beans.PropertyChangeEvent;\nimport java.beans.PropertyChangeListener;\nimport java.math.BigInteger;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Random;\nimport javax.swing.JButton;\nimport javax.swing.JFrame;\nimport javax.swing.JLabel;\nimport javax.swing.JPanel;\nimport javax.swing.JProgressBar;\nimport javax.swing.JScrollPane;\nimport javax.swing.JTextArea;\nimport javax.swing.JTextField;\nimport javax.swing.SwingWorker;\n\n\/**\n * Class to demonstrate the use of a SwingWorker thread.\n *\n *\/\npublic class SwingWorkerExample extends JFrame\n{\n  \/**\n   * Main entry point\n   *\/\n  public static void main(String&#x5B;] args)\n  {\n    EventQueue.invokeLater( new Runnable()\n      {\n        public void run()\n        {\n          JFrame frame = new SwingWorkerExample();\n          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);\n          frame.pack();\n          frame.setVisible(true);\n        }\n      }\n    );\n  }\n  \n  \/**\n   * Creates a new instance of SwingWorkerExample\n   *\/\n  public SwingWorkerExample()\n  {\n    Container panel = getContentPane();\n    panel.setLayout( new BorderLayout() );\n    panel.add( new InputPanel(), BorderLayout.NORTH );\n    m_textArea.setRows(30);\n    panel.add( new JScrollPane(m_textArea), BorderLayout.CENTER );\n    panel.add( m_progressBar, BorderLayout.SOUTH );\n    m_progressBar.setForeground(Color.RED);\n    m_progressBar.setStringPainted(true);\n  }\n  \n  \/\/\/\/ Inner classes \/\/\/\/\/\n  \n  \/**\n   * Input panel to allow user to enter values, and start generation\n   *\/\n  private class InputPanel extends JPanel implements ActionListener\n  {\n    InputPanel()\n    {\n      add( new JLabel(&quot;Bits:&quot;) );\n      add(m_bits);\n      add( new JLabel(&quot;# of primes to generate:&quot;) );\n      add(m_total);\n      add(m_startButton);\n      m_startButton.addActionListener(this);\n      add(m_cancelButton);\n      m_cancelButton.setEnabled(false);\n      m_cancelButton.addActionListener( new ActionListener()\n        {\n          public void actionPerformed(ActionEvent event)\n          {\n            m_task.cancel(true);\n          }\n        }\n      );\n    }\n    \n    \/**\n     * Invoked on start button click\n     *\/\n    public void actionPerformed(ActionEvent e)\n    {\n      try\n      {\n        \/\/ Extract the input values\n        \/\/ (Can generate NumberFormatExceptions)\n        int bits = Integer.parseInt(m_bits.getText());\n        int count = Integer.parseInt(m_total.getText());\n        \/\/ Prevent multiple starts during work in progress\n        m_startButton.setEnabled(false);\n        \/\/ Allow for cancellation\n        m_cancelButton.setEnabled(true);\n        \/\/ Clear the text area\n        m_textArea.setText(&quot;&quot;);\n        \/\/ Create the worker task\n        m_task = new PrimeNumbersTask(bits, count);\n        \/\/ Set up to listen for progress changes\n        m_task.addPropertyChangeListener( new PropertyChangeListener()\n        {\n          public  void propertyChange(PropertyChangeEvent evt)\n          {\n            if (&quot;progress&quot;.equals(evt.getPropertyName()))\n            {\n              m_progressBar.setValue((Integer)evt.getNewValue());\n            }\n          }\n        }\n        );\n        \/\/ Start the task thread\n        m_task.execute();\n      }\n      catch (NumberFormatException nfe)\n      {\n        \/\/ No nothing (silently ignore the button click)\n      }\n    }\n  }\n  \n  \n  \/**\n   * Class to calculate a set of prime m_numbers in a worker thread.\n   *\/\n  private class PrimeNumbersTask extends SwingWorker&lt; List&lt;BigInteger&gt;, BigInteger &gt;\n  {\n    \/**\n     * Constructor.\n     * @param bitCount the number of bits for a prime\n     * @param primeCount the number of primes to generate\n     *\/\n    PrimeNumbersTask(int bitCount, int primeCount)\n    {\n      m_bitCount = bitCount;\n      m_primeCount = primeCount;\n    }\n    \n    \/**\n     * This method runs in the background, in the worker thread.\n     *\/\n    @Override\n    public List&lt;BigInteger&gt; doInBackground()\n    {\n      while ( (m_numbers.size() &lt; m_primeCount) &amp;&amp; ! isCancelled())\n      {\n        BigInteger number = nextPrimeNumber();\n        m_numbers.add(number);\n        publish(number);\n        setProgress(100 * m_numbers.size() \/ m_primeCount);\n      }\n      return m_numbers;\n    }\n    \n    \/**\n     * Receives data chunks from the publish method\n     * asynchronously on the Event Dispatch Thread.\n     *\/\n    @Override\n    protected void process(List&lt;BigInteger&gt; chunks)\n    {\n      for (BigInteger number : chunks)\n      {\n        m_textArea.append(number + &quot;\\n&quot;);\n      }\n    }\n    \n    \/**\n     * Automatically invoked after the doBackground() method is finished.\n     * This method runs in the context of the Event Dispatch Thread\n     *\/\n    @Override\n    protected void done()\n    {\n      m_textArea.append(&quot;Generated total of &quot; + m_numbers.size() +\n        &quot; primes of size &quot; + m_bitCount + &quot; bits.\\n&quot;);\n      \/\/ Reset state of buttons.\n      m_startButton.setEnabled(true);\n      m_cancelButton.setEnabled(false);\n    }\n    \n    \/**\n     * Returns the next prime number\n     *\/\n    private BigInteger nextPrimeNumber()\n    {\n      return BigInteger.probablePrime(100, m_randomGenerator);\n    }\n    \n    \/\/\/\/ Private data \/\/\/\/\n    private final int m_bitCount;\n    private final int m_primeCount;\n    private ArrayList&lt;BigInteger&gt; m_numbers = new ArrayList&lt;BigInteger&gt;();\n    private Random m_randomGenerator = new Random(0);\n  }\n  \n  \/\/\/\/ Private data \/\/\/\/\/\n  private JTextField m_bits = new JTextField(4);\n  private JTextField m_total = new JTextField(4);\n  private JButton m_startButton = new JButton(&quot;Start&quot;);\n  private JButton m_cancelButton = new JButton(&quot;Cancel&quot;);\n  private JTextArea m_textArea = new JTextArea();\n  private final JProgressBar m_progressBar = new JProgressBar(0, 100);\n  private PrimeNumbersTask m_task;\n}\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">which produces something like:<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"alignleft size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"883\" height=\"1024\" src=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-4.22.16-PM-883x1024.png\" alt=\"\" class=\"wp-image-427\" srcset=\"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-4.22.16-PM-883x1024.png 883w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-4.22.16-PM-259x300.png 259w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-4.22.16-PM-768x891.png 768w, https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-content\/uploads\/2021\/02\/Screen-Shot-2021-02-05-at-4.22.16-PM.png 988w\" sizes=\"auto, (max-width: 883px) 100vw, 883px\" \/><\/figure><\/div>\n\n\n\n<div style=\"height:27px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">I had told it to generate 15 primes of 10 bits each.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Swing presents some particular problems relating to multi-threaded programs. Since every Java GUI program is always multi-threaded, it&#8217;s important to understand what these problems are, and how to circumvent them. The Problem Swing was not designed to be fully thread-safe.&nbsp; Instead, it was designed in such a way that only code running in the event [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":19,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_eb_attr":"","ocean_front_end_style_editor":"no","ocean_post_layout":"left-sidebar","ocean_both_sidebars_style":"","ocean_both_sidebars_content_width":0,"ocean_both_sidebars_sidebars_width":0,"ocean_sidebar":"ocs-course-topics-sidebar","ocean_second_sidebar":"0","ocean_disable_margins":"enable","ocean_add_body_class":"","ocean_shortcode_before_top_bar":"","ocean_shortcode_after_top_bar":"","ocean_shortcode_before_header":"","ocean_shortcode_after_header":"","ocean_has_shortcode":"","ocean_shortcode_after_title":"","ocean_shortcode_before_footer_widgets":"","ocean_shortcode_after_footer_widgets":"","ocean_shortcode_before_footer_bottom":"","ocean_shortcode_after_footer_bottom":"","ocean_display_top_bar":"default","ocean_display_header":"default","ocean_header_style":"","ocean_center_header_left_menu":"0","ocean_custom_header_template":"0","ocean_custom_logo":0,"ocean_custom_retina_logo":0,"ocean_custom_logo_max_width":0,"ocean_custom_logo_tablet_max_width":0,"ocean_custom_logo_mobile_max_width":0,"ocean_custom_logo_max_height":0,"ocean_custom_logo_tablet_max_height":0,"ocean_custom_logo_mobile_max_height":0,"ocean_header_custom_menu":"0","ocean_menu_typo_font_family":"0","ocean_menu_typo_font_subset":"","ocean_menu_typo_font_size":0,"ocean_menu_typo_font_size_tablet":0,"ocean_menu_typo_font_size_mobile":0,"ocean_menu_typo_font_size_unit":"px","ocean_menu_typo_font_weight":"","ocean_menu_typo_font_weight_tablet":"","ocean_menu_typo_font_weight_mobile":"","ocean_menu_typo_transform":"","ocean_menu_typo_transform_tablet":"","ocean_menu_typo_transform_mobile":"","ocean_menu_typo_line_height":0,"ocean_menu_typo_line_height_tablet":0,"ocean_menu_typo_line_height_mobile":0,"ocean_menu_typo_line_height_unit":"","ocean_menu_typo_spacing":0,"ocean_menu_typo_spacing_tablet":0,"ocean_menu_typo_spacing_mobile":0,"ocean_menu_typo_spacing_unit":"","ocean_menu_link_color":"","ocean_menu_link_color_hover":"","ocean_menu_link_color_active":"","ocean_menu_link_background":"","ocean_menu_link_hover_background":"","ocean_menu_link_active_background":"","ocean_menu_social_links_bg":"","ocean_menu_social_hover_links_bg":"","ocean_menu_social_links_color":"","ocean_menu_social_hover_links_color":"","ocean_disable_title":"default","ocean_disable_heading":"default","ocean_post_title":"","ocean_post_subheading":"","ocean_post_title_style":"","ocean_post_title_background_color":"","ocean_post_title_background":0,"ocean_post_title_bg_image_position":"","ocean_post_title_bg_image_attachment":"","ocean_post_title_bg_image_repeat":"","ocean_post_title_bg_image_size":"","ocean_post_title_height":0,"ocean_post_title_bg_overlay":0.5,"ocean_post_title_bg_overlay_color":"","ocean_disable_breadcrumbs":"default","ocean_breadcrumbs_color":"","ocean_breadcrumbs_separator_color":"","ocean_breadcrumbs_links_color":"","ocean_breadcrumbs_links_hover_color":"","ocean_display_footer_widgets":"default","ocean_display_footer_bottom":"default","ocean_custom_footer_template":"0","footnotes":""},"class_list":["post-397","page","type-page","status-publish","hentry","entry"],"_links":{"self":[{"href":"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-json\/wp\/v2\/pages\/397","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-json\/wp\/v2\/comments?post=397"}],"version-history":[{"count":12,"href":"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-json\/wp\/v2\/pages\/397\/revisions"}],"predecessor-version":[{"id":428,"href":"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-json\/wp\/v2\/pages\/397\/revisions\/428"}],"up":[{"embeddable":true,"href":"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-json\/wp\/v2\/pages\/19"}],"wp:attachment":[{"href":"https:\/\/bhiggs.x10hosting.com\/HighOctaneJava\/wp-json\/wp\/v2\/media?parent=397"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}