Background:
The Java Virtual Machine (JVM) has many strengths, but one I've always found interesting is multithreaded applications. This applet demonstrates how the JVM manages multiple threads running with varied priorities for execution. In this simulation, each thread is represented by a progress bar. Also, each thread has exactly the same amount of "work" to do.
To use this applet, set the priority for each thread with the drop-down combo box, then click the "Start" button. A setting of "4" is the highest priority and "1" is the lowest priorty.
How it works: The applet itself is a thread running at "MAX_PRIORITY" and updates the progress bar depending on the progress of each thread. Because Java (and all programming languages) must process programs in a linear fashion, the launching of the threads is done sequencially (from top to bottom, in this case). It is this which causes the threads to finish at different times, even when the priorities are set to the same level.
Producer/Consumer Simulation in a Java Applet
ThreadRace Applet |
ThreadRace.java
/* ThreadRace.java Chad Therrien
*
* This applet used RacerThread.java to demonstrate how Java handles multiple
* threads with different priorities. Each thread can be set to one of four
* values and then all are launched with the 'Start' button.
* Finishing order of the threads is noted on the applet GUI.
*/
import java.awt.*;
import java.awt.event.*;
import java.applet.Applet;
import java.awt.*;
import javax.swing.*;
public class ThreadRace extends JApplet implements Runnable, ItemListener, ActionListener
{
JProgressBar pBar1, pBar2, pBar3, pBar4;
Thread mainThread;
RacerThread threadOne = new RacerThread("one",1);
RacerThread threadTwo = new RacerThread("two",2);
RacerThread threadThree = new RacerThread("three",3);
RacerThread threadFour = new RacerThread("four",4);
Boolean runMain = false;
Integer winState = 1;
Boolean fin1 = false;
Boolean fin2 = false;
Boolean fin3 = false;
Boolean fin4 = false;
Button startButton;
JLabel label3,label4,label5,label6,label7;
JComboBox priority1, priority2, priority3, priority4;
public void init()
{
Container contentPane = getContentPane();
contentPane.setLayout(new GridLayout(5, 3));
JLabel label1 = new JLabel("Thread Race Applet");
contentPane.add(label1);
JLabel label8 = new JLabel("Finish Order:");
contentPane.add(label8);
startButton = new Button("Start Race");
contentPane.add(startButton);
pBar1 = new JProgressBar();
pBar1.setMinimum(threadOne.getMin());
pBar1.setMaximum(threadOne.getMax());
pBar1.setOrientation(JProgressBar.HORIZONTAL);
pBar1.setForeground(Color.blue);
pBar1.setValue(0);
pBar1.setStringPainted(true);
pBar1.setBorder(BorderFactory.createRaisedBevelBorder());
pBar2 = new JProgressBar();
pBar2.setMinimum(threadTwo.getMin());
pBar2.setMaximum(threadTwo.getMax());
pBar2.setOrientation(JProgressBar.HORIZONTAL);
pBar2.setForeground(Color.green);
pBar2.setStringPainted(true);
pBar2.setBorder(BorderFactory.createRaisedBevelBorder());
pBar3 = new JProgressBar();
pBar3.setMinimum(threadThree.getMin());
pBar3.setMaximum(threadThree.getMax());
pBar3.setOrientation(JProgressBar.HORIZONTAL);
pBar3.setForeground(Color.cyan);
pBar3.setStringPainted(true);
pBar3.setBorder(BorderFactory.createRaisedBevelBorder());
pBar4 = new JProgressBar();
pBar4.setMinimum(threadFour.getMin());
pBar4.setMaximum(threadFour.getMax());
pBar4.setOrientation(JProgressBar.HORIZONTAL);
pBar4.setForeground(Color.red);
pBar4.setStringPainted(true);
pBar4.setBorder(BorderFactory.createRaisedBevelBorder());
contentPane.add(pBar1);
label3 = new JLabel("");
contentPane.add(label3);
priority1 = new JComboBox();
priority1.addItem("1");
priority1.addItem("2");
priority1.addItem("3");
priority1.addItem("4");
priority1.setSelectedItem("1");
contentPane.add(priority1);
contentPane.add(pBar2);
label4 = new JLabel("");
contentPane.add(label4);
priority2 = new JComboBox();
priority2.addItem("1");
priority2.addItem("2");
priority2.addItem("3");
priority2.addItem("4");
priority2.setSelectedItem("2");
contentPane.add(priority2);
contentPane.add(pBar3);
label5 = new JLabel("");
contentPane.add(label5);
priority3 = new JComboBox();
priority3.addItem("1");
priority3.addItem("2");
priority3.addItem("3");
priority3.addItem("4");
priority3.setSelectedItem("3");
contentPane.add(priority3);
contentPane.add(pBar4);
label6 = new JLabel("");
contentPane.add(label6);
priority4 = new JComboBox();
priority4.addItem("1");
priority4.addItem("2");
priority4.addItem("3");
priority4.addItem("4");
priority4.setSelectedItem("4");
contentPane.add(priority4);
priority1.addItemListener(this);
priority2.addItemListener(this);
priority3.addItemListener(this);
priority4.addItemListener(this);
startButton.addActionListener(this);
}
public void run()
{
while(true)
{
pBar1.setValue(threadOne.getCount());
pBar2.setValue(threadTwo.getCount());
pBar3.setValue(threadThree.getCount());
pBar4.setValue(threadFour.getCount());
try
{
Thread.sleep(100);
}catch(Exception e){}
if (!fin1&&threadOne.isDone())
{
fin1 = true;
label3.setText(" "+winState.toString());
winState++;
}
if (!fin2&&threadTwo.isDone())
{
fin2 = true;
label4.setText(" "+winState.toString());
winState++;
}
if (!fin3&&threadThree.isDone())
{
fin3 = true;
label5.setText(" "+winState.toString());
winState++;
}
if (!fin4&&threadFour.isDone())
{
fin4 = true;
label6.setText(" "+winState.toString());
winState++;
}
}
}
public void start()
{
mainThread = new Thread(this);
mainThread.setPriority(Thread.MAX_PRIORITY);
mainThread.start();
}
public void itemStateChanged(ItemEvent e)
{
threadOne.setPriority(priority1.getSelectedIndex()+1);
threadTwo.setPriority(priority2.getSelectedIndex()+1);
threadThree.setPriority(priority3.getSelectedIndex()+1);
threadFour.setPriority(priority4.getSelectedIndex()+1);
}
public void actionPerformed(ActionEvent event)
{
winState = 1;
fin1 = false;
fin2 = false;
fin3 = false;
fin4 = false;
threadOne = new RacerThread("one",priority1.getSelectedIndex()+1);
threadTwo = new RacerThread("two",priority2.getSelectedIndex()+1);
threadThree = new RacerThread("three",priority3.getSelectedIndex()+1);
threadFour = new RacerThread("four",priority4.getSelectedIndex()+1);
threadOne.start();
threadTwo.start();
threadThree.start();
threadFour.start();
label3.setText("");
label4.setText("");
label5.setText("");
label6.setText("");
}
}
|
RacerThread.java
/* RacerThread.java Chad Therrien
*
* This thread is used in ThreadRace.java. The constructor allows the priority
* to be set, or can be set dynamically. Starting the thread will invoke it to
* count to a preset goal and then stop.
*/
import javax.swing.*;
class RacerThread implements Runnable
{
private final int countGoal = 500000000;
private Thread thread;
private int counter = 0;
volatile boolean runFlag = false;
public RacerThread()
//Instantiate default
{
thread = new Thread(this);
}
public RacerThread(String name)
//Instantiate with name default priority
{
thread = new Thread(this,name);
}
public RacerThread(String name,int priority)
//Instantiate with name and priority
{
thread = new Thread(this, name);
thread.setPriority(priority);
}
public void setPriority(int priority)
//Priority mutator
{
thread.setPriority(priority);
}
public int getMin()
//Min count accessor
{
return 0;
}
public int getMax()
//Max count accessor
{
return countGoal;
}
public int getPriority()
//Priority accessor
{
return thread.getPriority();
}
public void start()
//Start thread - executes run() method
{
thread.start();
}
public void reset()
//Reset current thread status
{
counter = 0;
runFlag=false;
thread.stop();
}
public void run()
//Set done flag to false and begin counting (work of thread)
{
runFlag=false;
while(counter < countGoal)
{
counter++;
}
runFlag=true; //setting done flag to true when complete
}
public boolean isDone()
//Done flag accessor
{
return runFlag;
}
public int getCount()
//Current count accessor
{
return counter;
}
}
|