Slide handouts 4.
Course book: Chapter 16
A more
general introduction to the subject can be found in the following trail from
Sun: http://java.sun.com/docs/books/tutorial/essential/threads/
It might
also be a good idea to take a look at the mentioned methods on the Thread class
in the Java API.
The topic
of this lecture is thread programming - the concept of being able to run
multiple processes simultaneously within a single Java program. The intention
is to give you a basic understanding of how threads are used and what the main
challenges are. How to program multithreaded systems in a safe and sensible
manner is a very big topic and not the scope of this
lecture.
When studying for this
lecture the important parts to understand are:
·
What
is meant by the concept “thread”.
·
In
what situations it is advantageous (or necessary) to use threads.
·
How
the two different ways of creating threads in Java are used (extending Thread
or implementing Runnable)
·
The
difference between the methods start() and run() and how they are related.
·
What
a daemon-thread is.
·
What
does it mean when a thread is blocked.
·
What
does a race condition mean?
·
What
type of problems might arise when multiple threads access the same objects
simultaneously and how the keyword “synchronized” is used to
prevent them.
·
What
problems the use of “synchronized” might introduce, i.e. deadlocks.
·
How
the scheduling of thread-execution can be managed using priorities.
Exercise 1. Download SlowPrinter.java. This program currently prints the
contents of 3 arrays in a sequential manner. After printing each String it
sleeps for a while, so the execution is quite slow done sequentially.
SlowPrinter has two methods, one called blockingPrint()and one called nonBlockingPrint(). Currently the method nonBlockingPrint()will throw a NotImplementedException, to signal that the method is not yet implemented. In this exercise you
will need to implement this method.
The method blockingPrint()is a blocking method in the sense
that a call of blockingPrint()doesn’t return until the entire contents of the method has been
executed. You might say that blockingPrint()borrows the calling methods thread and doesn’t release it until
it’s done.
The
assignment is to implement nonBlockingPrint(), so it does exactly the same as blockingPrint()but in a non-blocking/asynchronous
way. (See slide 6).
Your
version of nonBlockingPrint()is to start by creating its own
thread and then use this thread to print with, so the calling methods thread can
return immediately and continue its execution in parallel with the printing.
Exercise 2. The program JoinExercise.java (download it from the course page)
shows how threads can wait for each other using the join()method:
(a)
Explain
why this program writes what it does.
(b)
Threads
can be created either by extending class Thread or by implementing Runnable. If all you need in your thread is to have a run() method you should not extend Thread but implement Runnable. Furthermore using inner classes
tends to make the code less readable and classes less reusable. Change the
program so:
Exercise 3. In the program SyncExercise.java two threads are requesting the same
locks.
Explain why
the program writes as it does by describing which threads exist and what locks
they each hold or wait for:
(a)
Shortly
after the program has started.
(b)
Approx.
0.5 second after the program has started.
(c)
Approx.
1.0 second after the program has started.
(d)
Approx.
1.5 second after the program has started.
(e)
What
do you call the situation that arises when the program doesn’t end ?
(a) Change the code to use separate threads
for the secretary and a student and a boss giving her assignments at random
intervals. Argue for each method you synchronize, and each place you use a
synchronized block. Remember that just because the program does as you expect,
it is not a guarantee that it is thread safe.
(b) Enhance the code such that if there
are no jobs for the secretary she will wait() for jobs
(c) Optional ! Enhance the code in such a way that sometimes the
boss can give flowers to the secretary. When he does, she will be so happy that
she processes her jobs 3 times faster than usual for the next 10 seconds.
Exercise 5: This exercise is about creating your own
utility class called MyTimer. The intention is for
other classes that need to do something at certain time-intervals to reuse the MyTimer class.
We will
assume that the classes whose instances need to be notified by MyTimer (that is have some method
that needs to be called at regular time-intervals) have to implement the
following interface:
public interface MyTimerListener{
public void timeAction( ); //The action to be performed
}
We will
also assume that MyTimer has the following public
interface:
public class MyTimer{
public MyTimer(MyTimerListener
timerListener, int timeBetweenCalls){
// Insert code here
}
}
Here timerListener is a reference to the object that needs to
have its timeAction( ) method called at a regular intervals specified by the
integer parameter timeBetweenCalls (in
milliseconds).
(a)
Implement the class MyTimer.
(b) Now
write a test that shows that MyTimer works. You might
for instance write two classes that both implement MyTimerListener
and have instances of the first class print an X every half second, and
instances of the second class print an O every third second.
(c) Optional ! Modify the MyTimer class so it takes an
argument “repetitions” telling how many times to call the
associated MyTimerListener before stopping.
(d) Optional ! Write
a method MyTimer.waitForStop() that is a blocking call and doesn’t return until
the MyTimer instance it is waiting for is done with
it’s repetitions. Make sure MyTimer is stopped
safely, that is - do not use the deprecated Thread.stop() method !
(e) Optional ! Write
a method MyTimer.deactivate() that stops MyTimer temporarily
from calling timeAction(). MyTimer
is to resume calling timeAction() again when someone calls MyTimer.activate()
(write this method as well). Do not use the deprecated methods Thread.suspend() and Thread.resume()
!