Threads II. Review A thread is a single flow of control through a program Java is...

Preview:

Citation preview

Threads II

Review

• A thread is a single flow of control through a program

• Java is multithreaded—several threads may be executing “simultaneously”

• If you have a computer with more than one CPU, it may actually be true that more than one thread is executing at a time

• For most of us, the operating system just rapidly switches back and forth between threads

• In Java, a Thread is an object that contains information about a thread

Why care about Threads?

• We will see that a knowledge of threads allows us to:– Pause the program for a given length of time

– Create an animation that can be controlled by the GUI

– Prevent certain kinds of mysterious bug

– Put the program, rather than the user, in charge of the user interaction

– Reduce the interdependencies between classes

Sleeping

• To pause your program for a given length of time, use– try { Thread.sleep(1000); }

catch (InterruptedException e) { }

• A millisecond is 1/1000 of a second• sleep only works for the current Thread • Your program will pause for at least the given

number of milliseconds—possibly more• A thread can only put itself to sleep; it cannot put

a different thread to sleep

State transitions

• A Thread can be in one of four states:– Ready: all set to run

– Running: actually doing something

– Waiting, or blocked: needs something

– Dead: will never do anything again

ready

waiting

running deadstart

Two ways of creating Threads

• You can extend the Thread class:– class Animation extends Thread {…}– Limiting, since you can only extend one class

• Or you can implement the Runnable interface:– class Animation implements Runnable {…}– requires public void run( )

• I recommend the second for most programs

Extending Thread• You can create a new thread by extending the Thread class:

class Animation extends Thread { public void run( ) { code for this thread } Anything else you want in this class}

Animation anim = new Animation( ); anim.start( );– A newly created Thread is in the Ready state

• start( ) is a request to the scheduler to run the Thread --it may not happen right away

• The Thread should eventually enter the Running state

• The problem with this approach is that a class can only extend one other class—and you may want it extend something else

Implementing Runnable

• You can create a new thread by implementing the Runnable interface: – class Animation implements Runnable {…}– Animation anim = new Animation( ); Thread myThread = new Thread(anim); myThread.start( );

• The Runnable interface requires a public void run( ) method– This is the “main” method of your new Thread – You do not write the start() method—it’s provided by Java

• As always, start( ) is a request to the scheduler to run the Thread--it may not happen right away

Things a Thread can do

• Thread.sleep(milliseconds)• yield( )• Thread me = currentThread( );• int myPriority = me.getPriority( );• me.setPriority(NORM_PRIORITY);• if (otherThread.isAlive( )) { … }• join(otherThread);

Things a Thread should NOT do

• A Thread should control its own destiny, not be told by other Threads what to do

• Deprecated methods:– someOtherThread.stop( )– someOtherThread.suspend( )– someOtherThread.resume( )

• Outside control of Threads turned out to be a Bad Idea– The other Thread may be halfway through performing

an operation, for example

• Don’t use deprecated methods!

Controlling animation I

• If you look at a typical GUI program, the main method:– Sets up the GUI, including the Listeners– Quits!

• Any program with a GUI automatically gets an additional thread to handle the Listeners– After that, additional work is done from the Listeners

• You can exploit this:– Instead of quitting, have the main method call an

animation method (or any other compute-intensive method you wish to control) after the GUI is set up

Controlling animation II public static void main(String args[]) {

ThreadTest test = new ThreadTest(); test.show(); test.doSomething(); // To avoid static poisoning

}

void doSomething() { while (true) { try { Thread.sleep(500); } catch (InterruptedException e) {} if (OK) { // boolean instance variable, set by Buttons count++; // int instance variable countTextField.setText(count + ""); }

} }

Another way to control animation

• Let the main program quit...– But first, set up another Thread to do the animation (or

other compute-intensive) work in a run() method

– start() this other Thread

• Again, the other Thread can be controlled by setting flags (such as the OK variable in the previous example) from the GUI

The need for synchronization

• What gets printed as the value of k?• This is a trivial example of what is, in general, a

very difficult problem

int k = 0;

Thread #1: k = k + 1;

Thread #2: System.out.print(k);

Synchronizing tasks

• You can synchronize on an object:– synchronized (obj) { code that uses/modifies obj }– This is a statement type, like a while or switch– No other synchronized statement can use or modify this

object at the same time

• You can synchronize a method:– synchronized void addOne(arg1, arg2, ...)

{ code }– Only one synchronized method in a class can be used at

a time (but other methods could be used)

• Synchronization is a tool, not a solution—multithreading is in general a very hard problem

Example: producer-consumer

• Suppose you have two tasks (Threads), a producer and a consumer, and one “box” to put things in– The box can hold only (in this example) a single value

– The producer computes a new value and puts it in the box, but only if the box is empty

– The consumer gets and uses a new value from the box, but only if the box is full

• This problem cannot be solved reliably and safely without synchronization

Methods needed for the producer/consumer problem

• public final void wait() throws InterruptedException– Should be used within a synchronized object or method – Causes the current Thread to wait until another Thread calls

notify() or notifyAll() for this object

• public final void notify()– Wakes up some one Thread that is waiting on this Object

• public final void notifyAll()– Wakes up all Threads that are waiting on this Object

• These methods are defined in Object, hence can be used in any Object

The producer

• First, some instance variables: public boolean available = false; public String inputText;

• The producer: public synchronized void provideInput(String

theInput) { while (available) { try { wait(); } catch (InterruptedException e) { } } inputText = theInput; available = true; notifyAll();}

The consumer

• This method must be within the same class (so that it synchronizes on the same object): public synchronized String waitForInput() {

while (! available) { try { wait(); } catch (InterruptedException e) {} } available = false; notifyAll(); return inputText;}

MVC

• In the Model-View-Controller Design Pattern,– The Model does the actual work

– The Model should be fully independent of the View

– The View displays what is going on in the Model

– The Model does have to provide access methods, so that the View can do its job

– The Model should not know about the View, but—• When something happens in the Model, how does the View

know that it need to update the display?

• This problem often leads people to have the Model call methods in the View—this is a poor solution

Class Observable• To make an Object observable, have it extend the

class java.util.Observable– Sorry, this is a class, not an interface

• Your object then inherits the following methods (among others):– addObserver(Observer o)

• Allows Observer objects to see this one

– setChanged()• Marks this object as having been changed in some way

– notifyObservers(Object arg)• If this object has been changed, notify all its Observers and

clear the changed flag. arg is made available to Observers

interface Observer• To implement Observer, supply the following

method:– void update(Observable o, Object arg)

• This method is called whenever the observed object is changed

• You will also need to add this object to the list of Observers for the object you want to observe:– model.addObserver(this);

• With this scheme, the model can be completely independent– Admittedly, the model “knows” it is being observed, but– It doesn’t know about any specific objects or classes

Observer/Observable summary public class Model extends Observable {

... setChanged(); notifyObservers(arg);}

public class View implements Observer { ... model.addObserver(this); ... public void update(Observable o, Object arg) { ... }}

The End

Recommended