Mega Code Archive

 
Categories / Java / Threads
 

This program demonstrates that a thread that runs in parallel with the event dispatch thread can cause errors in Swing components.

/*    This program is a part of the companion code for Core Java 8th ed.    (http://horstmann.com/corejava)    This program is free software: you can redistribute it and/or modify    it under the terms of the GNU General Public License as published by    the Free Software Foundation, either version 3 of the License, or    (at your option) any later version.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    GNU General Public License for more details.    You should have received a copy of the GNU General Public License    along with this program.  If not, see <http://www.gnu.org/licenses/>. */ import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Random; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JPanel; /**  * This program demonstrates that a thread that runs in parallel with the event dispatch thread can  * cause errors in Swing components.  * @version 1.23 2007-05-17  * @author Cay Horstmann  */ public class SwingThreadTest {    public static void main(String[] args)    {       EventQueue.invokeLater(new Runnable()          {             public void run()             {                SwingThreadFrame frame = new SwingThreadFrame();                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);                frame.setVisible(true);             }          });    } } /**  * This frame has two buttons to fill a combo box from a separate thread. The "Good" button uses the  * event queue, the "Bad" button modifies the combo box directly.  */ class SwingThreadFrame extends JFrame {    public SwingThreadFrame()    {       setTitle("SwingThreadTest");       final JComboBox combo = new JComboBox();       combo.insertItemAt(Integer.MAX_VALUE, 0);       combo.setPrototypeDisplayValue(combo.getItemAt(0));       combo.setSelectedIndex(0);       JPanel panel = new JPanel();       JButton goodButton = new JButton("Good");       goodButton.addActionListener(new ActionListener()          {             public void actionPerformed(ActionEvent event)             {                new Thread(new GoodWorkerRunnable(combo)).start();             }          });       panel.add(goodButton);       JButton badButton = new JButton("Bad");       badButton.addActionListener(new ActionListener()          {             public void actionPerformed(ActionEvent event)             {                new Thread(new BadWorkerRunnable(combo)).start();             }          });       panel.add(badButton);       panel.add(combo);       add(panel);       pack();    } } /**  * This runnable modifies a combo box by randomly adding and removing numbers. This can result in  * errors because the combo box methods are not synchronized and both the worker thread and the  * event dispatch thread access the combo box.  */ class BadWorkerRunnable implements Runnable {    public BadWorkerRunnable(JComboBox aCombo)    {       combo = aCombo;       generator = new Random();    }    public void run()    {       try       {          while (true)          {             int i = Math.abs(generator.nextInt());             if (i % 2 == 0) combo.insertItemAt(i, 0);             else if (combo.getItemCount() > 0) combo.removeItemAt(i % combo.getItemCount());             Thread.sleep(1);          }       }       catch (InterruptedException e)       {       }    }    private JComboBox combo;    private Random generator; } /**  * This runnable modifies a combo box by randomly adding and removing numbers. In order to ensure  * that the combo box is not corrupted, the editing operations are forwarded to the event dispatch  * thread.  */ class GoodWorkerRunnable implements Runnable {    public GoodWorkerRunnable(JComboBox aCombo)    {       combo = aCombo;       generator = new Random();    }    public void run()    {       try       {          while (true)          {             EventQueue.invokeLater(new Runnable()                {                   public void run()                   {                      int i = Math.abs(generator.nextInt());                      if (i % 2 == 0) combo.insertItemAt(i, 0);                      else if (combo.getItemCount() > 0) combo.removeItemAt(i                            % combo.getItemCount());                   }                });             Thread.sleep(1);          }       }       catch (InterruptedException e)       {       }    }    private JComboBox combo;    private Random generator; }