400 likes | 410 Views
Explore thread usage in real-time systems with examples of threads, bounce programs, and ball movement simulations. Learn to create interactive interfaces using Java.
E N D
ISYE 7210--Simulation of Real-Time Systems Fall 2005Threads, Runnable, Interfaces7210 Class Web site: www.chmsr.gatech.edu/ISyE7210/Horstmann & Cornel (7th ed) Code Download Web site:www.horstmann.com/corejava.html Christine M. Mitchell Center for Human-Machine Systems Research (chmsr) School of Industrial and Systems Engineering (chmsr lab) ISyE Main, Room 426, 404 385-0363 (office) ISyE Groseclose, Room 334, 404 894-4321 {cm}@chmsr.gatech.edu
Examples of Thread Use Bounce Program (1): Bounce Class • Bounce: Selfish thread example • Classes in Bounce program • Bounce • BounceFrame extends JFrame • BallPanel extends JPanel • Ball • Control program: BounceFrame
Examples of Thread Use Bounce Program (1): Bounce Class import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.util.*; import javax.swing.*; public class Bounce { public static void main(String[] args) { JFrame frame = new BounceFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } }//end Bounce class
Examples of Thread Use Bounce Program (1): BounceFrame Class public BounceFrame() { setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); setTitle("Bounce"); panel = new BallPanel(); add(panel, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(); addButton( buttonPanel, "Start", new ActionListener() { public void actionPerformed(ActionEvent event) { addBall(); } }); • Constructs JFame, title, “Bounce” • Constructspanel, BallPanel • Addspanel to (JF)ame • ConstructsbuttonPanel, JPanel • Calls addButton( ) to create “Start”, JButton, which calls addBall( ) public class BounceFrame extends JFrame { private BallPanel panel; public static final int DEFAULT_WIDTH = 450; public static final int DEFAULT_HEIGHT = 350; public static final int STEPS = 1000; public static final int DELAY = 3;
Examples of Thread Use Bounce Program (1): BounceFrame Class public void addButton (Container c, String title, ActionListener listener) { JButton button = new JButton(title); c.add(button); button.addActionListener(listener); } public void addBall() { try { Ball ball = new Ball(); panel.add(ball); for (int i = 1; i <= STEPS; i++) { ball.move(panel.getBounds()); panel.paint(panel.getGraphics()); Thread.sleep(DELAY); } } catch (InterruptedException e){ } } • addButton( )creates a “Close” button, JButton • Close button action: exit program • Adds new button to Container • addBall(…)creates a ball, adds it to panel, & executes loop ball movement //imports addButton(buttonPanel, "Close", new ActionListener() { public void actionPerformed(ActionEvent event) { System.exit(0); } });
Examples of Thread Use (1): BallPanel Class //imports public class BallPanel extends JPanel { private ArrayList<Ball> balls = new ArrayList<Ball>(); public void add(Ball b) { balls.add(b); } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; for (Ball b : balls) { g2.fill(b.getShape()); } } //end paintComponent } /end BallPanel • Creates a ballPanel instance of JPanel • Creates an ArrayLists of balls • add(…) adds aBall to balls
Examples of Thread Use Bounce Program (1): Ball Class if (x + XSIZE >= bounds.getMaxX()) { x = bounds.getMaxX() - XSIZE; dx = -dx; } if (y < bounds.getMinY()) { y = bounds.getMinY(); dy = -dy; } if (y + YSIZE >= bounds.getMaxY()) { y = bounds.getMaxY() - YSIZE; dy = -dy; } } public Ellipse2D getShape() { return new Ellipse2D.Double(x, y, XSIZE, YSIZE); } } //end Ball class • Moves ball if an edge is reached //imports public class Ball { private static final int XSIZE = 15; private static final int YSIZE = 15; private double x = 0; private double y = 0; private double dx = 1; private double dy = 1; public void move(Rectangle2D bounds) { x += dx; y += dy; if (x < bounds.getMinX()) { x = bounds.getMinX(); dx = -dx; }
Examples of Thread Use BounceProgram (1): BounceFrame class public class BounceFrame extendsJFrame …. public void addBall() { try { Ball ball = new Ball(); panel.add(ball); for (int i = 1; i <= STEPS; i++) { ball.move(panel.getBounds()); panel.paint(panel.getGraphics()); Thread.sleep(DELAY); } //end for: moves ball } //end try • BounceFrame: addBall( ) • Consumes all resources • Executes a for loop 1000 times • Calls Thread.sleep(5000); • Cannot interrupt for 5 ms • Program can not “hear” while loop executes STEP times
Examples of Thread Use BounceThread Program (2): BounceThread Class • Multi-thread example • User-controlled resources • Start: BounceThread:main(…) • Classes • BounceThread • BounceFrame extends JFrame • BallRunnable • BallPanel extends JPanel • Ball
Examples of Thread Use BounceThread Program (2): BounceThread Class • Two threads: threads handle • Bouncing balls • Interface events //BounceThread.java import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.util.*; import javax.swing.*; /** Shows an animated bouncing ball. */ public class BounceThread { public static void main(String[] args) { JFrame frame = new BounceFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); }}
Examples of Thread Use BounceThread Program (2): BounceFrame Class panel = new BallPanel(); add(panel, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(); addButton(buttonPanel, "Start", new ActionListener() { public void actionPerformed(ActionEvent event) { addBall();} }); //end addButton( ) for start button addButton(buttonPanel, "Close", new ActionListener() { public void actionPerformed(ActionEvent event) { System.exit(0); } }); add(buttonPanel, BorderLayout.SOUTH); }); //end addButton( ) for close button • Creates graphical thread: Bouncing ball • Creates • Instance of JFrame • panel, BallPanel • Buttons for “Start” & “Close” //imports public class BounceFrame extendsJFrame { private BallPanel panel; public static final int DEFAULT_WIDTH = 450; public static final int DEFAULT_HEIGHT = 350; public static final int STEPS = 1000; public static final int DELAY = 3; public BounceFrame() { setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); setTitle("Bounce");
Examples of Thread Use BounceThread Program (2): BounceFrame Class //imports public void addButton(Container c, String title, ActionListener listener) { JButton button = new JButton(title); c.add(button); button.addActionListener(listener); } public void addBall() { Ball b = new Ball(); panel.add(b); Runnable r = new BallRunnable(b, panel); Thread t = new Thread(r); t.start( ); } } //end BouceFrame • addButton( ) • Creates button, JButton • Adds button to c, Continer • addBall ( ) • Creates aBall, Ball • Adds aBall to panel • Creates r, an instance of BallRunable(…) • Passes BallRunable aBall & panel • Creates t, Thread • Calls t.start()
Runnable Interface • java.lang Interface Runnable • void run( ) • Object implementing interface Runnable • Creates a thread • Start the thread: start( ) causes object's run( ) to execute • run( ) can be called in that separately executing thread
Examples of Thread Use BounceThread Program (2): BallRunable Class • Runs code in a separate thread • Subclass Thread • Put code within run( ) public BallRunnable(Ball aBall, Component aComponent) { ball = aBall; component = aComponent; } public void run() { try { for (int i = 1; i <= STEPS; i++) { ball.move(component.getBounds()); component.repaint(); Thread.sleep(DELAY); } } catch (InterruptedException e) { } } } //end BallRunnable class //imports class BallRunnable implements Runnable { private Ball ball; private Component component; public static final int STEPS = 1000; public static final int DELAY = 5; /** Constructs the runnable. aBall & aPanel on which the ball bounces */
Examples of Thread Use BounceThread Program (2): BallPanel Class • Much like BallCanvas • Creates an ArrayList, balls • Adds aBall to balls • Paints graphics //import class BallPanel extends JPanel { private ArrayList<Ball> balls = new ArrayList<Ball>(); public void add(Ball b) { balls.add(b); } public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; for (Ball b : balls) { g2.fill(b.getShape()); } } } //end BallPanel
Examples of Thread Use BounceThread Program (2): Ball Class if (x + XSIZE >= bounds.getMaxX()) { x = bounds.getMaxX() - XSIZE; dx = -dx; } if (y < bounds.getMinY()) { y = bounds.getMinY(); dy = -dy; } if (y + YSIZE >= bounds.getMaxY()) { y = bounds.getMaxY() - YSIZE; dy = -dy; } } public Ellipse2D getShape() { return new Ellipse2D.Double(x, y, XSIZE, YSIZE); } } //end Ball class • Moves ball if an edge is reached //imports public class Ball { private static final int XSIZE = 15; private static final int YSIZE = 15; private double x = 0; private double y = 0; private double dx = 1; private double dy = 1; public void move(Rectangle2D bounds) { x += dx; y += dy; if (x < bounds.getMinX()) { x = bounds.getMinX(); dx = -dx; }
Examples of Thread Use BounceThread Program (2): BounceThread Running • Usetwo threads • bouncing ball • GUI events • start( ) makes a new thread Runnable • start( ) calls run() //public class BounceFrame extends JFrame public void addBall() { Ball b = new Ball(); panel.add(b); Runnable r = new BallRunnable(b, panel); Thread t = new Thread(r); t.start( ); } } //BallRunnable class public void run() { try {for (int i = 1; i <= STEPS; i++) { ball.move(component.getBounds()); component.repaint(); Thread.sleep(DELAY); } } catch (InterruptedException e) { } } //end run( )
Examples of Thread Use (2): BounceThread Running //public class BounceFrame extends JFrame public void addBall() { Ball b = new Ball(); panel.add(b); Runnable r = new BallRunnable(b, panel); Thread t = new Thread(r); t.start( ); } } • Never call run( ) {“code”} directly • a thread’s start ( ) indirectly calls run ( ){code} • Code for a new thread executes in run( ) • Thead calls static Thread.sleep (DELAY) //BallRunnable class public void run() { try {for (int i = 1; i <= STEPS; i++) { ball.move(component.getBounds()); component.repaint(); Thread.sleep(DELAY); } } catch (InterruptedException e) { } } //end run( )
How to Use Threads • Event-dispatching thread • event-dispatchingthread holds code for Swing event-handling • Ensures an event handler finishes executing before the next one executes • To avoid deadlock, Swing components are created, modified, and queried only from the event-dispatching thread • Avoiding thread problems • Use invokeLater( ) to create the GUI on the event-dispatching thread private static void createAndShowGUI() { //Create and set up the window. frame = new JFrame("FocusConceptsDemo"); frame = new JFrame("FocusConceptsDemo"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); . …… }
How to Use Threads Event-dispatching thread private static void createAndShowGUI() { . …… } public static void main(String[] args) { //Schedule a job for the event-dispatching thread: //creating and showing this application's GUI javax.swing.SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } } ); //end call to SwingUtilities.invokeLater to createAndShowGUI() } //end main
How to Use Threads • Using the invokeLater method • invokeLater( ) request the event-dispatching thread to run certain code • Code is contained in run( ) of a Runnable object • Specify the Runnable object as the argument to invokeLater • invokeLater( ) returns immediately, without waiting for the event-dispatching thread to execute the code. /** example of code using invokeLater (anObject) */ Runnable updateAComponent = new Runnable() { public void run() { component.doSomething(); } }; SwingUtilities.invokeLater(updateAComponent); //SwingUtilities.invokeLater run( )
How to Use Threads • Using the invokeAndWait ( ) method • Similar to invokeLater( ) • invokeAndWait( ) does not return until the event-dispatching thread as executed code • Avoid using invokeAndWait( ) • invokeAndWait( ) can cause deadlock • Use invokeLater( ) instead
How to Use Threads • Using threads to improve performance • Move a time-consuming initialization task out of the main thread, so that GUI comes up faster • Examples of time-consuming tasks include • Making extensive calculations • Blocking for network or disk I/O (loading images, for example) • Move a time-consuming task out of the event-dispatching thread, so that the GUI remains responsive • Perform an operation repeatedly • wait( ) for messages from other programs
Synchronizing Threads • Concurrently running threads share data • Producer/consumer scenarios • Producer generates a stream of data • Consumer consumes the data • For example • One thread (the producer) writes data to a file • Another thread (the consumer) reads data from the same file • Concurrent threads share the same resource: share a file • Thus, threads must be synchronized • Use Object’s wait & notifyAll methods Example: new implementations of get and put for threads • wait on each other • notify each other of their activities
Synchronizing Threads: Consumer • Concurrently running threads share data • Example: new implementations of get and put public synchronized int get() { while (available == false) { try wait(); // wait for Producer to put value } catch (InterruptedException e) { } } //end while available = false; notifyAll(); // notify Producer that value has been retrieved return contents; }//end get()
Synchronizing Threads: Producer • Concurrently running threads share data • Example: new implementations of get and put public synchronized void put(int value) { while (available == true) { try { wait();// wait for Consumer to get value } catch (InterruptedException e) { } } contents = value; available = true; notifyAll(); // notify Consumer that value has been set } //end put
Synchronizing Threads • get( ) loops until the Producer has produced a new value • Each time through the loop, get( ) calls the wait( ) • wait( ) relinquishes lock held by the Consumer on CubbyHole • Producer can get( ) and update CubbyHole • Consumer waits for notification from Producer • If the Producer puts something in the CubbyHole, Produces notifies Consumer by calling notifyAll( ) • Consumer is no longer waiting • available is now true • loop exits • get( )returns value in the CubbyHole • put( ) waits for Consumer to consume current value before allowing Producer to produce a new one
Synchronizing Threads • Get( ) loops until Producer has produced new value • Object contains • wait( ) used in producer/consumer example • waits indefinitely for notification • Two other versions of the wait method • wait(long timeout) wait until the timeout period has elapsed • wait( ) for notification • Timed wait((long) delay) can • Synchronize threads • Replace sleep( ) • wait( ) and sleep( ) delay for requested amount of time • Easily wake up wait( ) with notify( ) • Sleeping thread, Thread.sleep(DELAY) cannot be awakened prematurely
Synchronizing Threads: wait(…) • wait(long timeout, int nanos) • Waits for notification or until timeout milliseconds plus nanos nanoseconds have elapsed. • Note: • Use timed wait methods to synchronize threads, • Use wait() methods to replace sleep • Both wait and sleep delay for the requested amount of time • Easily wake wait with a notify • A sleeping thread cannot be awakened prematurely • Note: Doesn't matter too much for threads that don't sleep for long, but it could be important for threads that sleep for minutes at a time.
How Sims will Use Threads & ‘Sleep: • Sim0, Sim1 public void simulate() Thread.sleep( (long) (delay )); • Sim2, Sim3 & 4 public synchronized void simulate() ….. ….. ….. try { wait(); // wait until 'notify()ed' } catch(InterruptedException ie) { continue; }
Simulator’s Main Loop--Simulator:Simulate( ) Simulator.java 506 public synchronized void simulate() { double delay; DecimalFormat delayfmt = new DecimalFormat("#.0"); boolean msgWaiting; if (_simControl != null) _simControl.updateStatus(iSimControl.PAUSED); // simulation loop 520 while (!_simulationFinished) { …. try { wait(); // wait until 'notify()ed' } catch(InterruptedException ie) { continue; } }
Simulator’s Main LoopSchedule a Wait Time—Time Until Next Event Simulator.java else // (!_simulationFinished) { if (!_clock.onFastTime()) // not onFastTime { 537 delay = ((double)(getNextEventTime() - _clock.updateSimTime()) / _clock.getSpeedFactor()) try { 549 wait( (int) (delay )); } catch (InterruptedException ie) { continue; } // try-catch 566 else //if (_clock.onFastTime())
Simulator’s Main LoopDiscrete-Event Processing Simulator.java 641 else if … try { _eventCal.processEvent(); } 661 } // if clock-not-paused } // simulation loop 663 } //end simulate( )
DefaultSimControl.javaThread of Execution DefaultSimControl.java 84 public class DefaultSimControl extends JFrame implements iSimControl, ActionListener, ItemListener { public DefaultSimControl() //constructor { super("Simulator Control"); ………. // (69) JButton _resumeB _resumeB = createControlButton("Start", RESUME_COLOR); cp.add(_resumeB); ………. }//end constructor
DefaultSimControl.javaThread of Execution DefaultSimControl.java 84 public class DefaultSimControl extends JFrame implements iSimControl, ActionListener, ItemListener { public DefaultSimControl() { super("Simulator Control"); ………. // (69) JButton _resumeB _resumeB = createControlButton("Start", RESUME_COLOR); cp.add(_resumeB); ………. }//end constructor 153 private JButton createControlButton(String name, Color buttonColor) { JButton controlB = new JButton(name); controlB.addActionListener(this); controlB.setBackground(buttonColor); controlB.setForeground(Color.black); controlB.setBorder(BorderFactory.createEtchedBorder()); controlB.setEnabled(false); return controlB; }
DefaultSimControl.javaThread of Execution 84 public class DefaultSimControl extends JFrame implements iSimControl, ActionListener, ItemListener { public DefaultSimControl() { super("Simulator Control"); ………. } SwingUtilities.invokeLater(changeControlDisplay); } public void updateStatus(int status) { final int simStatus = status; Runnable changeControlDisplay = new Runnable() { public void run() { switch(simStatus) SwingUtilities.invokeLater(changeControlDisplay);
DefaultSimControl.java & GUI Controller public DefaultSimControl() { super("Simulator Control"); public class DefaultSimControl extends JFrame implements iSimControl, ActionListener, ItemListener SwingUtilities.invokeLater(changeControlDisplay); } 250 public void actionPerformed(ActionEvent ev) …. 265 else if (source == _pauseB) { _pauseB.setEnabled(false); _resumeB.setEnabled(true); _realTimeB.setEnabled(false); _fastTimeB.setEnabled(false); _speedCBX.setEnabled(false);
GUI Controller 250 public void actionPerformed(ActionEvent ev) …. if (_FirstPause) { _resumeB.setText("Resume"); _FirstPause = false; } 280 _simulator.pause(); }
GUI Controller:Back to Simulator: Simulate Simulator.java 1045 public synchronized void pause() { 1049 _clock.pause(); //paused simulator if (_simControl != null) _simControl.updateStatus(iSimControl.PAUSED); //tell contrller if (_broadcaster != null) _broadcaster.pauseSim(getTimeNow()); //tell interface log("Simulation paused."); notifyAll(); //wake up threads } Clock.java 283 public void pause() { _pauseTime = _currentSimTime.getTime(); _paused = true; }