CS 4773 Object Oriented Systems Threads and Thread Synchronization
Topics for today:
- Threads
- Thread synchronization
Threads
There are two main ways to use threads in Java:
- Create an object with a class which extends the class Thread
- The constructor initializes the thread.
- When the thread's start method is called, the thread's
run method executes concurrently with other threads.
- Create an object of type Thread.
- Pass an object from a class which implements Runnable.
- When the thread is started, the run method of that
Runnable object is executed.
- Often, the Runnable is the same object that creates the thread.
When you declare a Thread variable with
Thread ping
the variable is initially null.
If an class implements Runnable it must have a run
method. Executing:
ping = new Thread(this)
creates a new thread which can execute the run method of the class.
The thread can be started with its start method:
ping.start();
At this point the thread is in its active state. It remains active
until it is stopped or it completes execution of its run method.
Ping Pong Application
PingPong.java is a thread that prints out a word a given number
of times with a given delay.
It also shows the number of active threads.
PingPongTest1.java
is an application that just starts two copies of PingPong.
Using join
Join suspends the caller until the thread has completed.
The PingPongTest2 application
waits for each thread to complete and
then prints a message.
It also has a method which shows the threads.
Thread States
- new: The thread has been created but not started, for example with
- runnable: The thread has been started and is in the ready queue.
- running: The thread is actually running on a CPU.
- suspended: The thread's suspend method has been called
while the thread was runnable or running.
It makes no further progress until its resume method is called.
- blocked: The thread is blocked from continuing because it requested
I/O, called sleep, called wait, or called join.
- suspended-blocked: A blocked thread was suspended by another thread
calling its suspend method.
- dead: The thread has terminated because it has completed its run
method or its stop method has been called.
Note: neither suspend nor stop should be used.
Synchronization in Java
Synchronization is done in Java using monitors.
Each instance of a class has its own monitor with one
(anonymous) condition variable.
Recall that a monitor is a compiler construct which allows only one
process to be active (own the monitor)
within the protected methods of the monitor.
In Java, by default, no methods of the object are protected.
You can protect methods by using the synchronized key word.
How to own a monitor of an object
- Execute code in a synchronized method of the object. This is the usual way.
- Execute code which is contained in a synchronized block as follows:
synchronized (obj) {
code goes here
}
The second method is unusual.
Protecting a critical section
If multiple threads are going to modify an ArrrayList,
all modifying methods must be synchronized:
ArrayList- list = new ArrayList
- ();
public synchronized void insertElement(Item a) {
list.add(a);
}
public synchronized void removeElement(Item a) {
list.remove(a);
}
public synchronized void showIt() {
for (Item it : list)
System.out.println(it.toString());
}
Note that the last one needs to be synchronized also so that the list
is not changed while it is being accessed.
Here are some of the important methods related to thread synchronization:
- public static native void sleep(long millis) throws InterruptedException
This method causes the calling thread to sleep for the given number of
milliseconds (more or less, according to the specification)
or until the thread's interrupt method is called.
- public final void join() throws InterruptedException
Waits until the given thread dies or the current thread is interrupted.
- public final void wait() throws InterruptedException
Waits to be notified by another thread or interrupted.
The current thread must own the object's monitor, that is be executing from
inside a synchronized method.
The thread releases ownership of the monitor.
When it is notified, it must regain ownership of the monitor before it
continues executing.
- public final native void notify()
Wakes up a single thread that is waiting on this object's monitor.
The current thread must own the object's monitor, that is be executing from
inside a synchronized method.
The current thread does not lose ownership of the monitor.
- public final native void notifyAll()
Wakes up all threads that are waiting on this object's monitor.
The current thread must own the object's monitor, that is be executing from
inside a synchronized method.
The current thread does not lose ownership of the monitor.
- public void interrupt()
Interrupts a thread.
This sets a flag in the thread which can be tested.
If the thread was block on sleep, wait or join,
an InterruptedException is thrown by that thread.
Note: this was not implemented in Java 1.0.
Waiting for a variable to change (without busy waiting)
public synchronized void test1() {
while (count == 0)
try {
wait();
catch (InterruptedException e) {}
...
}
public synchronized void test2() {
...
count++;
if (count == 1)
notify();
}
Note that the two methods must be in the same object (same monitor)
and executed by different threads.
AWT events and threads
When an event such as a mouse click or button push occurs, and event handler
is called by the thread that handles AWT events. When a button is pushed
it might call actionPerformed in a class.
In general, this should only use the CPU for a short time, or other AWT
events will be blocked.
The usual method for handling this is to have the actionPerformed
just set a variable and wake up or create a thread to handle the action.
Look at the ButtonThread example.
- The Calculator class wastes a given number of milliseconds either
directly or by starting a new thread.
- Button 1 uses this without a thread
- Button 2 creates a new thread to execute this.