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;
}
Related examples in the same category