Transcript Threads

Threads and Turns
26-Jul-16
Thread review

There are two ways to create a Thread object..

Extend Thread and supply a run method:



Implement Runnable:




class MyThread extends Thread {
public void run( ) { ... }
}
Thread someThread = new MyThread();
class Something implements Runnable {
public void run( ) { ... }
}
Something something = new Something();
Thread someThread = new Thread(something);
...And just one way to start a Thread running

someThread.start();
Random facts about Threads

Threads are Objects, with all that that implies


Every Thread has a name



You can specify the name when you construct the Thread, or just let Java
generate a name for the Thread
You can get and set the Thread’s name
Every Thread has a priority



Threads can be saved in variables, they have a toString() method, etc.
Higher priority Threads run in preference to lower priority Threads
You can get and set a Thread’s priority, but it’s seldom a good idea
Every Thread is either a daemon Thread or a non-daemon Thread



Java exits when all non-daemon Threads have quit running
Daemon Threads will die when Java exits
You can get and set the Thread’s daemon status
Monitors

Threads are synchronized by means of monitors

Any Object can be a monitor
A Thread that “holds” (or “has a lock on”) a monitor prevents any other
Thread from using that monitor

A synchronized statement uses an explicit object as a monitor



A synchronized instance method uses the instance (this) as a monitor


synchronized(SomeObject) { ... }
public synchronized void someMethod() { ... }
A synchronized static method uses the class’s Class object as a monitor


public static synchronized void someMethod() { ... }
If this is in class Thing, the Class object is given by Thing.class
Threads with monitors

The following methods (defined in the Object class) can only be executed
when the current Thread holds a monitor

monitor.notify()



monitor.notifyAll()



Wakes all Threads that are waiting on this monitor
After the current Thread relinquishes the lock, some one wakened Thread will get it and
be able to proceed
monitor.wait() and monitor.wait(long timeoutInMilliseconds)



Wakes some arbitrary Thread that is waiting on this monitor
The wakened Thread will be able to proceed after this current Thread relinquishes the
lock, and the wakened Thread gets it
This Thread relinquishes the lock, and becomes dormant until something wakes it
Things that can wake a dormant Thread are:
 Some other Thread invokes notify() or notifyAll()
 Some other Thread calls this Thread’s interrupt() method
 The timeout period has passed
 Some other random thing happens (no, seriously!)
Trying to execute one of the above methods when the current Thread does not
hold a monitor results in an IllegalMonitorStateException
How to wait




When a Thread waits, it’s because it’s waiting for something
However, a Thread may be awakened at any time, for the wrong
reason (or for no reason at all)
Therefore, a wait should always be performed within a loop
Here’s the idiom:


synchronized (obj) {
while (the thing I’m waiting for hasn’t happened) {
obj.wait();
}
// Do whatever it was I was waiting to do
Also, a wait method can throw an InterruptedException, so
you will need to put the above in a try/catch block
The Producer-Consumer problem

Sometimes you have two independent processes, one
producing results, and the other consuming them


You want the process to move along efficiently



For example, downloading a file or a Web page
The Producer shouldn’t have to wait for the Consumer to
take something before it can produce another good
The Consumer should take things as quickly as it can,
pausing only when it needs to wait for the Producer
In programming, we often have this problem when
dealing with Threads
 The data structure we need is a Queue
Implementing a Queue


We want a Queue that we can use for passing objects from one
Thread to another
We will define put(object) and object=get() methods



The Queue must be synchronized, because having two different Threads
modifying it “at the same time” could be disastrous
The Producer Thread needs to wait if (and only if) the Consumer Thread is
currently taking something off the queue
If the Consumer Thread wants to get something from the Queue, and the
Queue is empty, it has to wait for something to be put in the Queue


That is, get is a blocking operation
In the following code, I’ll use an ArrayList to implement the
Queue

This is not as efficient as it could be (it’s O(n)), but it’s fast enough for my
purposes
Queue code
import java.util.ArrayList;
public class Queue {
ArrayList list = new ArrayList();
public void put(Object obj) {
synchronized (list) {
list.add(obj);
list.notify();
}
}
public Object get() {
try {
synchronized (list) {
while (list.size() == 0) {
list.wait();
}
return list.remove(0);
}
} catch (InterruptedException e) { }
}
}
Two-way communication


A Queue is fine if one class is a producer and the other is a
consumer
However, what if one Thread wants to ask questions of the other
Thread?



Thread 1:
putRequest(request):
response = getResponse();
Thread 2:
request = getRequest();
response = doSomethingWith(request);
putResponse(response);
This requires a pair of Queues

In my code, I call this a “Channel”
Channel (a pair of Queues)

public class Channel {
Queue request = new Queue();
Queue response = new Queue();
public void putRequest(Object obj) {
request.put(obj);
}
public Object getRequest() {
return request.get();
}
public void putResponse(Object obj) {
response.put(obj);
}
}
public Object getResponse() {
return response.get();
}
Turn-based play

Sometimes we want to coordinate the activities of different Threads
One example is a game, where the various players take turns



Channel[] channels; // One for each player
public void run() {
Command request;
Object response;
while (true) {
for (int i = 0; i < channels.length; i++) {
do {
request = (Command) channels[i].getRequest();
response = doCommand(request);
channels[i].putResponse(response);
}
}
}
} while (!isAction(request));
Unmonitored Thread methods

The following methods can be used without getting a monitor

static Thread currentThread()


static void sleep(long ms)



Causes the current Thread to pause and allow other Threads to execute
boolean isAlive()


Causes the current Thread to become dormant for (at least) the given
number of milliseconds
The current Thread does not release any monitors it holds, so other
threads waiting for this monitor remain blocked
public static void yield()


Returns a reference to the currently executing Thread object
Tests if the given Thread is alive
void join()

Waits for the given Thread to die
The End