/* ThreadDemoSwing.java Application shows different states of threads. This demo uses deprecated thread methods to illustrate older "classic" thread state operations for cs322. The use of deprecated thread calls may cause demo to hang. javac -deprecation ThreadDemoSwing.java Thanks to Steven Stepanek for comments on sleep and "current thread". Mike Barnes 10/2/01 */ import java.io.*; import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ThreadDemoSwing extends JFrame implements ActionListener { private final int CMDS = 8; private final int START = 0, MAX = 1, MIN = 2, SUSPEND = 3, SLEEP = 4, INTERRUPT = 5, RESUME = 6, STOP = 7; private final Color GREEN = Color.green; private final Color RED = Color.red; private GridBagLayout gbLayout; private GridBagConstraints gbConstraints; private JLabel status, threadID[]; private Boxer aThread[]; private JMenuBar menuBar; private JMenu usageMenu; private JMenuItem usageModalItem, usageModelessItem; private UsageModelessDialog usageModelessDialog; private JButton cmd[][]; private JPanel display; // display thread boxes private int box[]; // hold length for aThread[i]'s box private String buttonLabel[] = {"start", "max pri", "min pri","suspend", "sleep", "interrupt", "resume", "stop"}; public Timer timer; public int count = 0; private static ThreadDemoSwing app; public static void main(String args[]) { app = new ThreadDemoSwing ("Thread Demo"); app.addWindowListener( new WindowAdapter() { public void windowClosing( WindowEvent e) {System.exit(0);}}); // app.setBounds(20,20, 600, 500); app.pack(); app.setVisible(true); app.showThread(); // show initial ThreadGroup // create and start Timer, Timer event every 20 seconds. app.timer = new Timer(10000, new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("timer active " + (++app.count)); app.showThread(); }}); app.timer.start(); } public void showThread() { System.out.println("threads are: " + Thread.activeCount()); Thread.currentThread().getThreadGroup().list(); } public ThreadDemoSwing (String frameTitle) { super(frameTitle); // call base constructor to set title int i, j; Container contentPane = getContentPane(); menuBar = new JMenuBar(); usageMenu = new JMenu("Help"); usageMenu.setMnemonic('H'); usageMenu.setToolTipText("How to run this thread demo"); usageModalItem = new JMenuItem("Usage modal"); usageMenu.add(usageModalItem); // create the dialog menu invokes usageModalItem.addActionListener( // anonymous inner class event handler new ActionListener() { public void actionPerformed(ActionEvent event) { JOptionPane.showMessageDialog( ThreadDemoSwing.this, "Threads are displayed in console window by timer every 10 secs.\n" + "Buttons on right control threads drawn as boxes.\n" + "Threads can hang application\n.", "Usage", JOptionPane.PLAIN_MESSAGE); }} ); usageModelessDialog = new UsageModelessDialog(this, false); usageModelessItem = new JMenuItem("Usage modeless"); usageMenu.add(usageModelessItem); usageModelessItem.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { usageModelessDialog.show();}} ); menuBar.add(usageMenu); setJMenuBar(menuBar); JPanel panel = new JPanel(); gbLayout = new GridBagLayout(); panel.setLayout(gbLayout); gbConstraints = new GridBagConstraints(); gbConstraints.fill = GridBagConstraints.BOTH; gbConstraints.insets = new Insets( 2, 5, 1, 5); status = new JLabel("Active threads " + Thread.activeCount()); status.setPreferredSize(new Dimension(400, 20)); aThread = new Boxer[3]; threadID = new JLabel[3]; box = new int[3]; display = new JPanel(); display.setPreferredSize(new Dimension(400, 200)); display.setBackground(Color.cyan); gbConstraints.insets = new Insets( 2, 10, 1, 10); cmd = new JButton[3][CMDS]; for (i = 0; i < 3; i++) { threadID[i] = new JLabel("Thread "+Integer.toString(i),JLabel.CENTER); addComponent(panel, threadID[i], 1, i, 1, 1); for (j = 0; j < CMDS; j++) { cmd[i][j] = new JButton(buttonLabel[j]); cmd[i][j].addActionListener(this); addComponent(panel, cmd[i][j], j + 2, i, 1, 1); } } gbConstraints.insets = new Insets( 2, 5, 1, 5); contentPane.add(display, BorderLayout.CENTER); contentPane.add(panel, BorderLayout.EAST); contentPane.add(status, BorderLayout.SOUTH); } /* * Place component at row, column with width, height. */ protected void addComponent( Container panel, Component c, int row, int col, int width, int height) { gbConstraints.gridy = row; gbConstraints.gridx = col; gbConstraints.gridwidth = width; gbConstraints.gridheight = height; gbLayout.setConstraints(c, gbConstraints); panel.add(c); } public void drawBox(int boxID) { // one copy of dislay's graphics Graphics dg = display.getGraphics(); if (box[boxID] == 99) dg.setColor(Color.cyan); else dg.setColor(Color.black); switch (boxID) { case 0 : dg.fillRect(16, 50, box[0], box[0]); break; case 1 : dg.fillRect(165, 50, box[1], box[1]); break; case 2 : dg.fillRect(285, 50, box[2], box[2]); } } public void setColumnButtons(int i, int k, Color aColor) { int j; for (j = 0; j < CMDS; j++) cmd[i][j].setBackground(Color.lightGray); cmd[i][k].setBackground(aColor); } public void actionPerformed (ActionEvent e) { int i, j, next; status.setText(""); // clear status line for (i = 0; i < 3; i++) for (j = 0; j < CMDS; j++) { if (e.getSource() == cmd[i][j]) { // see if valid thread has been stopped if(aThread[i] != null && aThread[i].lastState == 7) return; switch (j) { case START : // start aThread[i] = new Boxer(i); aThread[i].start(); setColumnButtons(i, j, GREEN); cmd[i][j].setEnabled(false); aThread[i].lastState = j; break; case MAX : // max priority aThread[i].setPriority(Thread.MAX_PRIORITY); setColumnButtons(i, j, GREEN); aThread[i].showStatus(); aThread[i].lastState = j; break; case MIN : // min priority aThread[i].setPriority(Thread.MIN_PRIORITY); setColumnButtons(i, j, GREEN); aThread[i].showStatus(); aThread[i].lastState = j; break; case SUSPEND : // suspend aThread[i].setSuspend(); setColumnButtons(i, j, RED); aThread[i].lastState = j; break; case SLEEP : // sleep aThread[i].setSleep(); break; case INTERRUPT : // interrupt next = (i + 1) % 3; if (aThread[next].lastState == STOP) break; aThread[next].setInterrupt(); setColumnButtons(next, j, RED); aThread[next].lastState = j; break; case RESUME : // resume aThread[i].setResume(); setColumnButtons(i, j, GREEN); aThread[i].lastState = j; break; case STOP : // stop box[i] = 99; // clear and don't draw anymore app.drawBox(i); aThread[i].stop(); setColumnButtons(i, j, RED); status.setText("Active threads " + Integer.toString(aThread[i].activeCount())); aThread[i].lastState = STOP; break; } break; // loop to find cmd source } } } class UsageModelessDialog extends JDialog implements ActionListener { JButton ok; JLabel label; public UsageModelessDialog(Frame owner, boolean modality) { super(owner, "Usage Modeless Dialog", modality); label = new JLabel("Modeless dialog, not in thread"); ok = new JButton("Ok"); ok.addActionListener(this); Container container = getContentPane(); container.add(label, BorderLayout.CENTER); container.add(ok, BorderLayout.SOUTH); pack(); } public void actionPerformed(ActionEvent e) { hide(); } } // Boxer computes size of boxes to draw as an activity class Boxer extends Thread { private int tid, lastState = 0; private boolean aSleep = false; public Boxer(int id) { tid = id; setName(Integer.toString(tid)); app.showThread(); } public void run() { int i; status.setText("Active threads " + activeCount() + " " + this.toString()); while(true) { if (aSleep) { setColumnButtons(tid, 4, RED); // set sleep button try { sleep(5000); } // sleep 5 secs. catch(InterruptedException ie) { System.out.println(toString() + " interrupt exception\n"); } if (lastState == SUSPEND) // suspended setColumnButtons(tid, 3, RED); else if (lastState == INTERRUPT) setColumnButtons(tid, 5, RED); else setColumnButtons(tid, lastState, GREEN); aSleep = false; } box[tid] = (box[tid] + 1 ) % 100; // increment box size app.drawBox(tid); // note drawing is in Swing thread yield(); } } public void setSleep() { aSleep = true; status.setText(toString() + " sleep"); } public void setInterrupt() { status.setText(toString() + " interruptted"); this.suspend(); } public void setSuspend() { status.setText(toString() + " suspend"); this.suspend(); } public void setResume() { status.setText(toString() + " resume"); this.resume(); } public void showStatus() { status.setText(toString()); } } }