Threads II

advertisement
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
waiting
start
ready
running
dead
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
int k = 0;
Thread #1:
k = k + 1;
Thread #2:
System.out.print(k);
• What gets printed as the value of k?
• This is a trivial example of what is, in general, a
very difficult problem
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
Download