SwingThreadTest.java Source code

Java tutorial

Introduction

Here is the source code for SwingThreadTest.java

Source

/*
   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;
}