Presentation is loading. Please wait.

Presentation is loading. Please wait.

1 Learning objectives By the end of this chapter you should be able to:  explain how concurrency is achieved by means of time-slicing;  distinguish between.

Similar presentations


Presentation on theme: "1 Learning objectives By the end of this chapter you should be able to:  explain how concurrency is achieved by means of time-slicing;  distinguish between."— Presentation transcript:

1 1 Learning objectives By the end of this chapter you should be able to:  explain how concurrency is achieved by means of time-slicing;  distinguish between threads and processes;  implement threads in Java;  explain the difference between asynchronous and synchronized thread execution;  explain the terms critical section and mutual exclusion, and describe how Java programs can be made to implement these concepts;  explain how busy waiting can be avoided in Java programs;  provide a state transition diagram to illustrate the thread life- cycle;  produce animated applications and applets. IM103 week 12 Multi-threaded programs

2 2 computers can appear to perform more than one task at any one time; if the computer only has one cpu, then this is achieved by some form of time-slicing; a running program is usually referred to as a process; two or more processes that run at the same time are called concurrent processes; when processes run concurrently each has its own area in memory where its program code and data are kept; each process's memory space is protected from any other process; all this is dealt with by the operating system. Multi- tasking and concurrent processes

3 3 there are times when we want a single program to perform two or more tasks at the same time; whereas two concurrent programs are known as processes, each separate task performed by a single program is known as a thread; a thread is referred to as a lightweight process, because it takes less of the system's resources to manage threads than it does to manage processes; threads do not have completely separate areas of memory - they can share code and data areas. managing threads, is the job of the JVM working in conjunction with the operating system. Threads

4 4 A simple counter

5 5 The aim when we press the "start" button the numbers 1 to 10 should keep flashing by in the window; pressing the "stop" button should stop this process; if we are using an EasyFrame, clicking on the crosshairs should terminate the application. In fact, CounterVersionOne, doesn't quite do the job. The CounterVersionOne class

6 6 CounterVersionOne - the problem private void startCounterRunning() { int count = 1; while(go) { counterWindow.setText("" + count); count++; if(count > 10) { count=1; } else if(e.getSource() == stopButton) { go = false; } The startCounterRunning method The event handler for the stop button

7 7 there is only one thread of control; the RunCounterVersionOne program starts with the first line of the main method and carries on to the end of this method; this involves creating a CounterVersionOne object and setting up the frame - and then waiting for the user to click the mouse; if the mouse is clicked on the "start" button then the loop is started and the numbers start flashing by; the whole program is now tied up in this loop; if the "stop" button is pressed, the program will never get the chance to process this event, because it is busy executing the loop. CounterVersionOne - the problem

8 8 The Thread class the Thread class provides a number of different methods that allow us to create and handle threads in Java programs; the Thread class implements an interface called Runnable ; this provides a method called run, which must be implemented; the code for this method determines the action that takes place when the thread is started; one of the simplest ways to create a thread is to extend the Thread class.

9 9 import java.awt.*; class CounterThread extends Thread { private TextField counterWindow; /* this is the window where the numbers are displayed */ private boolean go = true; // this variable controls the loop /* the text window where the numbers are displayed is sent in as a parameter to the constructor */ public CounterThread(TextField windowIn) { counterWindow = windowIn; } …………………………………………………………………………… The CounterThread class

10 ……………………………………………………………… public void run() // this method is not called directly { int count = 1; while(go) { counterWindow.setText("" + count); /* Some additional code is going to go here later to improve the program */ count++; if(count > 10) // reset the counter if it has gone over 10 { count=1; } // this method will stop the numbers being displayed public void finish() { go = false; } The CounterThread class … continued

11 11 import java.awt.*; import java.awt.event.*; class CounterVersionTwo extends Panel implements ActionListener { private Button startButton = new Button("Start"); private Button stopButton = new Button("Stop"); private TextField counterWindow = new TextField(); private CounterThread thread; public CounterVersionTwo() { add(startButton); add(stopButton); add(counterWindow); startButton.addActionListener(this); stopButton.addActionListener(this); } ………………………………………………………………… The CounterVersionTwo class

12 12 …………………………………………………………… public void actionPerformed(ActionEvent e) { if(e.getSource() == startButton) { //create a new thread thread = new CounterThread(counterWindow); // start the thread thread.start(); } else if(e.getSource() == stopButton) { // stop the thread thread.finish(); } The CounterVersionTwo class … continued

13 13 The CounterVersionTwo class … analysis pressing the "start" button creates a new thread and starts it running by calling the object's start method; this automatically calls the run method; the run method should not be called directly, but should always be called by invoking start. pressing the "stop" button calls the thread's finish method. if you run this class in an EasyFrame, then pressing "start" will cause the numbers to rush by in the display window; but if you press "stop", you will see that the program does not always respond immediately; instead it continues to display the numbers for a little while before actually stopping; if you do this a few times you will see that the time it takes between pressing the button and the thread actually stopping varies from one attempt to the next.

14 14 Thread execution and scheduling with a single processor each process or thread is given a a quantum of time on the CPU, then the next process or thread takes its turn; the responsibility for process scheduling with the operating system; in the case of multi-threaded Java programs this takes place in conjunction with the JVM; it is not possible for the programmer or user to predict the amount of time that will be allocated to each thread; the Thread class provides some useful methods:

15 15 The sleep method this method forces a thread to give up the CPU for a specified amount of time, even if it hasn't completed its quantum; the time interval, in milliseconds, is passed in as a parameter; during this time, other threads can be given the CPU; the sleep method throws an InterruptedException and must be enclosed in a try... catch block.

16 16 New version of the run method of the CounterThread class public void run() { int count = 1; while(go) { counterWindow.setText("" + count); try { sleep(1); //force the thread to sleep for 1 msec } catch(InterruptedException e) { } count++; if(count > 10) { count=1; } NOTE: If you do not want the thread to wait a specific period of time before resuming, then you can use yield rather than sleep.

17 17 sometimes it is not possible to extend the Thread class, because the class needs to extend another class; the Thread class provides an alternative constructor that takes as a parameter a Runnable object where it expects to find the code for the run method; the alternative approach therefore involves: creating a class that implements the Runnable interface; then declaring a separate Thread object, either within this class or as a separate class. An alternative implementation

18 18 import java.awt.*; class AlternativeCounter implements Runnable { private TextField counterWindow; private boolean go = true; /* a thread object is now created as an attribute of the class */ private Thread cThread = new Thread(this); public AlternativeCounter(TextField windowIn) { counterWindow = windowIn; } ………………………………………………………… The AlternativeCounter class

19 ………………………………………………………………… public void run() { int count = 1; while(go) { counterWindow.setText("" + count); count++; try { // the sleep method of the thread object is called cThread.sleep(1); } catch(InterruptedException e) { } if(count > 10) { count=1; } ………………………………………………………………… The AlternativeCounter class …… continued

20 20 …………………………………………………………… // a separate method is now required to start the thread public void begin() { cThread.start(); } public void finish() { go = false; } The AlternativeCounter class …… continued

21 21 The AlternativeCounter class : analysis Three changes have been made: a new Thread object is created as an attribute: the object where the run method is to be found is passed as a parameter; in this example, it is this object itself that we must pass in. in the run method, we can no longer call the sleep method of this object, because the AlternativeCounter class does not extend the Thread class - instead, we call the sleep method of the thread object; we have had to create a new method, begin, which calls the start method of cThread - we have had to do this because the AlternativeCounter class is not an extension of Thread, and therefore does not have a start method of its own. NOTE In order to make use of this new class we have to rewrite CounterVersionTwo :

22 import java.awt.*; import java.awt.event.*; class CounterVersionThree extends Panel implements ActionListener { private Button startButton = new Button("Start"); private Button stopButton = new Button("Stop"); private TextField counterWindow = new TextField(); /* we are now using the AlternativeCounter class instead of the CounterThread class that we used in version two */ private AlternativeCounter aCounter; public CounterVersionThree() { add(startButton); add(stopButton); add(counterWindow); startButton.addActionListener(this); stopButton.addActionListener(this); } …………………………………………. The CounterVersionThree class

23 23 ………………………………………………………… public void actionPerformed(ActionEvent e) { if(e.getSource() == startButton) { aCounter = new AlternativeCounter(counterWindow); /* this time we have to use the object's begin method; it does not have a start method as it is not an extension of Thread */ aCounter.begin(); } else if(e.getSource() == stopButton) { aCounter.finish(); } The CounterVersionThree class … continued

24 24 under normal circumstances the behaviour of two or more threads executing concurrently is asynchronous; we are not therefore able to predict which threads will be allocated CPU time at any given moment; sometimes we require two or more concurrently executing threads or processes to be co-ordinated - for example: a producer-consumer relationship, whereby one process is continually producing information that is required by another process; an example is a program that copies a file from one place to another; one process is responsible for reading the data, another for writing the data; this could be implemented by providing a buffer where the data that has been read is queued while it waits for the write process to access it and then remove it from the queue; problems would arise if the read process and the write process tried to access the buffer at the same time; we would need to treat the parts of the program that access the buffer as critical sections - that is, sections that can be accessed only by one process at a time. Synchronizing threads

25 25 implementing critical sections is known as mutual exclusion,; Java provides a mechanism for the implementation of mutual exclusion in multi-threaded program; Java provides for the creation of a monitor - a class whose methods can be accessed by only one thread at a time; this entails the use of the modifier synchronized in the method header. For example a Buffer class might have a read method declared as: public synchronized Object read() {..... } because it is synchronized, as soon as some object invokes this method a lock is placed on it; this means that no other object can access it until it has finished executing. Mutual exclusion

26 26 Mutual exclusion can cause a problem known as busy waiting; this means that the method that is being executed by a particular thread has to go round in a loop until some condition is met; as a consequence the CPU time is used just to keep the thread going round and round in this loop until it times out. For example consider the read and write methods in the buffer above. The read method would not be able to place any data in the buffer if the buffer were full; it would have to loop until some data was removed by the write method; conversely, the write method would not be able to obtain any data if the buffer were empty - it would have to wait for the read method to place some data there. Java provides methods to help avoid busy waiting situations; the Object class has a method called wait, which suspends the execution of a thread until it receives a message from another thread telling it to wake up; the methods notify and notifyall are used for the purpose of waking up other threads. The “busy waiting” problem

27 27 TERMINATED SLEEPING READY RUNNING WAITING BLOCKED dispatch timeout yield start stop block timeout or unblock wait sleep notify notifyall wakeup The state transition diagram for a thread

28 a thread is brought into existence by invoking its start method; at this point it goes into the ready state (waiting to be allocated time on the CPU); once it is dispatched (given CPU time), it is said to be in the running state. Once a thread is running, a number of things can happen to it: It can timeout and go back to the ready state. The programmer could force this to happen by ensuring that its yield method is invoked; The programmer can also arrange for the sleep method to be called, causing the thread to go into the sleeping state for a given period of time. When this time period has elapsed the thread wakes up and goes back to the ready state. The programmer can use the wait method to force the thread to go into the waiting state until a certain condition is met. Once the condition is met, the thread will be informed of this fact by a notify or notifyall method, and will return to the ready state; A thread can become blocked - this is normally because it is waiting for some input, or waiting for an output device to become available. The thread will return to the ready state when either the normal timeout period has elapsed or the input/output operation is completed. When the run method finishes the thread is terminated. NOTE: It is actually possible to use the stop method of Thread to terminate execution; however it can be very dangerous to stop a thread in the middle of its execution; it is far better to use a control variable instead, so that the thread terminates naturally. Thread states: explanation of state transition diagram

29 29 import java.awt.*; class AnimatedFace extends Canvas implements Runnable { private boolean isHappy; // a separate thread is required to run the animation private Thread thread1; public AnimatedFace() { isHappy = true; // create a new thread thread1 = new Thread(this); // start the thread thread1.start(); } ………………………………………………………………………………… The AnimatedFace class

30 ………………………………………………………………………………… public void run() { while(true) // a continuous loop { // on each iteration of the loop the mood is changed..... if(isHappy == true) { isHappy = false; } else { isHappy = true; } //..... and the face is repainted repaint(); try { thread1.sleep(1000); } catch(InterruptedException e) { } } …………………………………………………………………………… The AnimatedFace class …. continued

31 31 The AnimatedFace class …. continued ……………………………………………………………………… public void paint(Graphics g) { g.setColor(Color.red); g.drawOval(85,45,75,75); g.setColor(Color.blue); g.drawOval(100,65,10,10); g.drawOval(135,65,10,10); g.drawString("Animated Face", 80,155); if(isHappy == true) { // draw a smiling mouth g.drawArc(102,85,40,25,0,-180); } else { // draw a frowning mouth g.drawArc(102,85,40,25,0,180); }

32 32 the repaint method does not call the paint method directly; it actually calls a method called update ; the default version of the update method clears the whole display area, repaints it in its background colour, and then calls the paint method; going through this process each time is what gives rise to the flicker; we can reduce the flicker dramatically if we don't repaint the whole screen each time - just the bit that needs repainting; Reducing flicker

33 33 once the rest of the face has been painted the first time, it doesn't need to be painted again; first we re-write the paint method so that it draws everything but the mouth: Reducing flicker in the AnimatedFace class public void paint(Graphics g) { g.setColor(Color.red); g.drawOval(85,45,75,75); g.setColor(Color.blue); g.drawOval(100,65,10,10); g.drawOval(135,65,10,10); g.drawString("Animated Face", 80,155); }

34 Note we are not calling paint, as would be the case with the default update method; the paint method is called once only, when the graphic first becomes visible. Reducing flicker in the AnimatedFace class … continued Next, we override the update method: public void update(Graphics g) { // clear only the area that contains the mouth g.clearRect(102,85,42,27); // set the foreground colour g.setColor(Color.blue); if(isHappy == true) { // draw a smiling mouth g.drawArc(102,85,40,25,0,-180); } else { // draw a frowning mouth g.drawArc(102,85,40,25,0,180); }

35 35 record8.gifrecord7.gifrecord6.gifrecord5.gif record4.gifrecord3.gifrecord2.gifrecord1.gif An animated applet: the RecordApplet class

36 36 Analysis of the RecordApplet class The init method we place here any initialization routines that should happen only at this time: public void init() { allLoaded = false; setBackground(Color.white); image = new Image[numberOfImages]; sleepTime = Integer.parseInt(getParameter("sleep")); }

37 37 here we place the code that needs to be invoked each time the applet becomes visible; note that the attribute first is necessary because certain parts of the graphic need to be painted only on the first iteration of the loop. Analysis of the RecordApplet class … continued The start method public void start() { go = true; first = true; animationThread = new Thread(this); animationThread.start(); }

38 38 Analysis of the RecordApplet class … continued The run method starts with a conditional set of statements that are executed only if the images have not yet been loaded; loading the images from a remote site will take some time; it is useful to monitor the progress so that a user of the program is not left wondering what is going on; for this purpose we can use the MediaTracker class; we create a MediaTracker object; the constructor requires a parameter indicating on which component the images will eventually be drawn: MediaTracker tracker = new MediaTracker(this);

39 39 Analysis of the RecordApplet class … continued The run method … continued after declaring a String to hold the name of each image in turn, we then use a for loop to prepare for the loading of the eight images: for(int i = 0; i < numberOfImages; i++) { strImage = fileName + (i+1) + ".gif"; image[i] = getImage(getDocumentBase(),strImage); tracker.addImage(image[i],i); }

40 Analysis of the RecordApplet class … continued The run method … using the methods of the MediaTracker class the getImage method does not load the image; it forms an association between the image name and the file name; left to its own devices the JVM will load the image at such time as it is needed, namely when it is to be displayed; a better way for this to happen is to use the MediaTracker class; this is done by invoking the addImage method of the MediaTracker object that we declared earlier; this method adds the image to the list of images that are to be tracked; the relevant image is passed in as the first parameter to this method; the second parameter allows us to assign a unique integer id to this image so that we can, if we wish, refer to it later in other MediaTracker methods; once this process is complete for all eight images, we can then start the process of loading the images; we do this with the waitForAll method of MediaTracker, which starts the loading process, and then waits for completion. try { tracker.waitForAll(); } catch(InterruptedException e) { }

41 41 Analysis of the RecordApplet class … continued The run method … using the methods of the MediaTracker class once the process is complete, we use the i sErrorAny method to check that all the images have loaded successfully: allLoaded = !tracker.isErrorAny(); if there are any errors we display an appropriate message and end the run method: if(!allLoaded) { Graphics g = getGraphics(); g.drawString("Error loading images", 115, 40); return; } Note a single image can be tracked in the same way with the waitForID and isErrorID methods.

42 42 Analysis of the RecordApplet class … continued The run method … the main body while(go) { repaint(); try { animationThread.sleep(sleepTime); } catch(InterruptedException e) { } nextImage++; if(nextImage == 8) { nextImage = 0; }

43 43 Analysis of the RecordApplet class … continued The paint method called each time the object becomes visible. public void paint(Graphics g) { if(!allLoaded) { g.drawString("Loading images....", 115, 20); } else { g.clearRect(115,10,150,20); g.setFont(new Font("Dialog",Font.BOLD,20)); g.drawString("Java Record", 90, 20); }

44 44 public void update(Graphics g) { if(first) { paint(g); first = false; /* paint is only called on the first iteration of the loop */ } g.drawImage(image[nextImage], 65, 50, this); } Analysis of the RecordApplet class … continued The update method called when the screen is repainted; responsible for drawing each image in the sequence.

45 45 Analysis of the RecordApplet class … continued The stop method called when the user moves away from the page. public void stop() { go = false; }

46 46 The HTML code to load and run the applet with a sleep time of 100 msecs


Download ppt "1 Learning objectives By the end of this chapter you should be able to:  explain how concurrency is achieved by means of time-slicing;  distinguish between."

Similar presentations


Ads by Google