Chapter 1. Java Threads

errorhandleSoftware and s/w Development

Nov 18, 2013 (3 years and 11 months ago)

79 views



[ Team LiB ]

Chapter 1. Java Threads
KEY TOPICS
￿ What Is a Thread?
￿ Creating and Running Threads in Java
￿ Synchronization
￿ Using wait() and notify()
￿ The Java Event Model
￿ When to Use Threads
￿ When Not to Use Threads
￿ Sum It Up: Thread Pools
￿ Summary
It's lunchtime, and you decide to treat yourself to a meal at your favorite restaurant. You take a
seat and look around—the place is pretty empty. There's one waiter, one customer eating, and
you.
The waiter is helping the other customer, but oddly, you're being ignored. Even when you ask for a
menu, the waiter acts as if you're not there and just refills the other customer's beverage. Finally,
after the other customer leaves, the waiter acknowledges your existence and helps you.
So what is the problem? The waiter hasn't been fired, that's the problem.
Actually, the problem is that the waiter didn't multitask. A multitasking waiter could serve two or
more customers at once instead of waiting for one customer to finish before serving a new
customer.
The multitasking waiter is a rough analogy to how threads work in computer science. In this
chapter, we go over all about how Java threads work and how to synchronize them, and we teach
you the tips and tricks along the way.

[ Team LiB ]

[ Team LiB ]

What Is a Thread?
Imagine the multitasking waiter is your computer's processor and the customers are tasks. Each
Page
1
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm

task runs in its own thread, and a processor with a modern operating system can run many threads
concurrently. For example, you've probably downloaded a file from the Internet while writing a
paper at the same time.
Modern operating systems run threads concurrently by splitting a thread's task into smaller
chunks. This is called concurrency. One thread is executed for a small amount of time (time slices
).
Then the thread is pre-empted, enabling another thread to run, and so on, as shown in
Figure 1.1
.
The time slices are small enough so that it seems as if several things are happening at once.
Figure 1.1. Concurrency means running multiple threads on one
processor.

On machines with more than one processor, threads might actually run simultaneously, depending
on the JVM implementation.
[ Team LiB ]

[ Team LiB ]

Creating and Running Threads in Java
Java was designed with threads in mind, so you'll find it easier to work with threads in Java than in
many other languages. To create and start a new thread, just create an instance of the
Thread

object and call the
start()
method:
Thread myThread = new Thread();
myThread.start();
Of course, this code won't do anything useful because the thread isn't assigned a task. The JVM
creates a new system thread, starts it, and calls the
Thread
object's
run()
method. By default, the
run()
method doesn't do anything, so the thread dies.
If you want to give a thread a task, and I'm sure you do, give the
run()
method something to do.
You can do this in three basic ways:
￿ Extend the
Thread
class
￿ Implement the
Runnable
interface
￿ Use anonymous inner classes
Extending the Thread Class
A quick way to give a thread a task is simply to extend the
Thread
class and override the
run()

method:
Page
2
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm
public class MyThread extends Thread {

public void run() {
System.out.println("Do something cool here.");
}
}
Then create and start the thread the same way as before:
Thread myThread = new MyThread();
myThread.start();
Now you've got two threads running: the main thread and the thread you just started.
Implementing the Runnable Interface
Extending the
Thread
class is easy, but most of the time you probably don't want to write a new
class just to start a thread. For example, you might want a class that extends another class and
can also be run as a thread. In this case, implement the
Runnable
interface:
public class MyClass extends SomeOtherClass implements Runnable {

public MyClass() {
Thread thread = new Thread(this);
thread.start();
}
public void run() {
System.out.println("Do something cool here.");
}
}
In this example, the
MyClass
object starts a new thread on construction. The
Thread
class takes a
Runnable
object as a parameter in its constructor, and that
Runnable
is executed when the thread
is started.
Using Anonymous Inner Classes
Sometimes you want to spawn a new thread without the bother of creating a new class, or perhaps
it's not convenient to implement the
Runnable
interface. In this case, you can use an anonymous
inner class to start a new thread:
new Thread() {
public void run() {
System.out.println("Do something cool here.");
}
}.start();
This example is simple enough, but it can quickly become unreadable if the code in the
run()

method is too long. Use this one sparingly.
Waiting for a Thread to Finish
If you want your current thread to wait until a thread is finished, use the
join()
method:
Page
3
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm

myThread.join();
This could be useful when a player exits your game, when you want to make sure all threads are
finished before you do any cleanup.
Sleepy Threads
Sometimes your threads might get tired, and you'll be nice enough to give them a break. Now
you're thinking, "What? My threads get tired? This is too complicated!"
No, your threads don't really get tired. But sometimes you might need a thread to pause for a bit,
so use the static
sleep()
method:
Thread.sleep(1000);
This causes the currently running thread to sleep for 1000 milliseconds, or any amount of time you
choose. A sleeping thread doesn't consume any CPU time—so it doesn't even dream.
[ Team LiB ]

[ Team LiB ]

Synchronization
Great, now you've got some threads running and they're doing all sorts of cool things at once. It's
not all sunshine and lollipops, though—if you've got multiple threads trying to access the same
objects or variables, you can run into synchronization problems.
Why Synchronize?
Let's say you're creating a maze game. Any thread can set the position of the player, and any
thread can check to see if the player is at the exit. For simplicity, let's say the exit is at position x
= 0, y = 0.
public class Maze {

private int playerX;
private int playerY;

public boolean isAtExit() {
return (playerX == 0 && playerY == 0);
}

public void setPosition(int x, int y) {
playerX = x;
playerY = y;
}
}
Most of the time, this code works fine. But keep in mind that threads can be pre-empted at any
time. Imagine this scenario, in which the player moves from (1,0) to (0,1):
1.Starting off, the object's variables are
playerX
=
1
and
playerY
=
0
.
Page
4
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm
2.Thread A calls
setPosition(0,1)
.
3.The line
playerX = x;
is executed. Now
playerX
=
0
.
4.Thread A is pre-empted by Thread B.
5.Thread B calls
isAtExit()
.
6.Currently,
playerX
=
0
and
playerY
=
0
, so
isAtExit()
returns
true
!
In this scenario, the player is reported as solving the maze when it's not the case. To fix this, you
need to make sure the
setPosition()
and
isAtExit()
methods can't execute at the same time.
How to Synchronize
Enter the synchronized keyword. In the maze example, if you make the methods synchronized,
only one method can run at a time.
Here's the updated, thread-safe code:
public class Maze {

private int playerX;
private int playerY;

public synchronized boolean isAtExit() {
return (playerX == 0 && playerY == 0);
}

public synchronized void setPosition(int x, int y) {
playerX = x;
playerY = y;
}
}
When the JVM executes a synchronized method, it acquires a lock
on that object. Only one lock can
be acquired on an object at a time. The lock is released when the method is finished executing
either by returning normally or by throwing an exception.
So, if one synchronized method owns a lock, no other synchronized method can run until the lock
is released.
You can think of locks as a lock on a restroom door. Only one person is in the restroom at a time.
The door is unlocked when the person leaves or, in the case of an exception, when the person
jumps out the window.

Besides method synchronization, there's also object synchronization. Object synchronization
enables you to treat any object as the lock—with method synchronization, the current instance
(
this
) is the lock. Method synchronization is essentially shorthand for object synchronization with
this
. For example, from the previous maze code, the method
public synchronized void setPosition(int x, int y) {
playerX = x;
playerY = y;
Page
5
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm
}
is essentially the same as this:
public void setPosition(int x, int y) {
synchronized(this) {
playerX = x;
playerY = y;
}
}
The only exception is that the second example has some extra bytecode instructions.
Object synchronization is useful when you need more than one lock, when you need to acquire a
lock on something other than
this
, or when you don't need to synchronize an entire method.
A lock can be any object, even arrays—basically, anything except primitive types. If you need to
roll your own lock, just create a plain Object:
Object myLock = new Object();
...
synchronized (myLock) {
...
}
What to Synchronize
But what should you synchronize? The answer is any time two or more threads will access the
same object or field.
What Not to Synchronize
When synchronizing your code, the general rule is not to oversynchronize—don't synchronize more
code than you have to. Doing so creates unnecessary delays when two or more threads try to
execute the same synchronized block of code.
For example, don't synchronize an entire method if only parts of the method need to be
synchronized. Instead, just put a synchronized block around the critical parts of code:
public void myMethod() {
synchronized(this) {
// code that needs to be synchronized
}
// code that is already thread-safe
}
Also, you don't have to synchronize a method that uses only local variables. Local variables are
stored on the stack, and each thread has its own separate stack, so there isn't a chance of running
into synchronization problems. For example, this method doesn't need to be synchronized because
it uses only local variables:
public int square(int n) {
int s = n * n;
return s;
Page
6
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm

}
Finally, don't worry about synchronizing code that isn't accessed by multiple threads. However, if
you know that some code is accessed by only one thread and you don't synchronize, be sure to
mention in your JavaDoc comments that the code isn't thread-safe. By doing this, you'll know you
have to change it if multiple threads in a future version access that code.
If you're not sure what threads are accessing your code, just print the name of the currently
running thread to the console:
System.out.println(Thread.currentThread().getName());
Avoiding Deadlock
Deadlock is the result of two threads that stall because they are waiting on each other to do
something. Consider this example:
1.Thread A acquires lock 1.
2.Thread B acquires lock 2.
3.Thread B waits for lock 1 to be released.
4.Thread A waits for lock 2 to be released.
As you can see, both threads are waiting on the lock that the other has, so they both stall
indefinitely.
Deadlock can occur as soon as you have multiple threads trying to acquire multiple locks out of
order.
How do you avoid deadlock? The best way is to simply write your synchronization code in such a
way that it cannot occur. Think about which threads acquire which locks and in what order.
Carefully try to consider every possibility.
If you think your game might be stalling because of deadlock, there are ways to detect it. As of
version 1.4.1 of the HotSpot VM, Sun has provided a deadlock detector. Run your game from a
console, and when it stalls, press Ctrl+\ (or Ctrl+break, in Windows). The VM displays information
on the state of threads, whether they are waiting on anything, and whether deadlock is detected.
[ Team LiB ]

[ Team LiB ]

Using wait() and notify()
Let's say you have two threads and they need to talk to each other. For example, let's say Thread
A is waiting on Thread B to send a message:
// Thread A
public void waitForMessage() {
while (hasMessage == false) {
Thread.sleep(100);
}
}
Page
7
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm

// Thread B
public void setMessage(String message) {
...
hasMessage = true;
}
Although this works, it's a clunky solution. Thread A has to constantly check whether Thread B has
sent the message every 100 milliseconds, or 10 times a second. Thread A could oversleep and be
late in getting the message. Also, what would happen if several threads were waiting for a
message? Wouldn't it be nice if Thread A could just stay idle and be notified when Thread B sends
the message?
Lucky for us, the
wait()
and
notify()
methods provide this capability.
The
wait()
method is used in synchronized blocks of code. When the
wait()
method executes, the
lock is released and the thread waits to be notified.
The
notify()
method is also used in a synchronized block of code. The
notify()
method notifies
one thread waiting on the same lock. If several threads are waiting on the lock, one of them is
notified randomly.
Here's the updated message code:
// Thread A
public synchronized void waitForMessage() {
try {
wait();
}
catch (InterruptedException ex) { }
}

// Thread B
public synchronized void setMessage(String message) {
...
notify();
}
After Thread B calls
notify()
and leaves its synchronized method (releasing the lock on
this
),
Thread A reacquires the lock and finishes its synchronized block of code. In this case, it just
returns.
You can also choose to wait for a maximum amount of time. The
wait()
method can take a
maximum amount of time to wait as a parameter:
wait(100);
If the thread is never notified, this is equivalent to putting the thread to sleep for the specified
amount of time. Unfortunately, there's no way to tell whether the
wait()
method returned because
of a timeout or because the thread was notified.
A second notify method,
notifyAll()
, notifies all threads waiting on the lock, instead of just one.
The
wait()
,
notify()
, and
notifyAll()
methods are methods of the Object class, so any Java
Page
8
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm



object has these methods—just like any Java object can be used as a lock.

[ Team LiB ]

[ Team LiB ]

The Java Event Model
You might think your game has only one thread and you don't have to worry about
synchronization, but that's not the case. All graphical applications have at least two threads that
can run your code: the main thread and the AWT event dispatch thread.
The main thread is (surprise!) the main thread of your program. It starts execution with the
main
()
method of your main class.
The AWT event dispatch thread handles user-input events: mouse clicks, keyboard presses, and
other events such as window resizing. We'll talk about these input events later in
Chapter 3
,
"Interactivity and User Interfaces," but for now, just know that these input events can access your
code through the AWT event dispatch thread.

[ Team LiB ]

[ Team LiB ]

When to Use Threads
Use threads whenever it will provide a more enjoyable experience for the user. This means any
time some code can stall or take a long time, run the code in another thread so the user doesn't
think your game has stalled.
For example, use threads in these situations:
￿ When loading lots of files from the local file system
￿ When doing any network communication, such as sending high scores to a server
￿ When doing any massive calculations, such as terrain generation
[ Team LiB ]

[ Team LiB ]

When Not to Use Threads
When you look at any game, you'll notice a lot of things going on at once—enemies running
around, doors opening, bullets flying, and so on. This leads some people to think, "I know, every
enemy runs in its own thread," but this is not the case. Not only is this a waste of resources—
running too many threads at once can drain the system—but this creates problems such as these:
￿ An enemy could move in the middle of a draw operation, temporarily showing the enemy in
two different places at once.
Page
9
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm

￿ The time slices of each thread could be unbalanced, leading to jerky or inconsistent
movement.
￿ Synchronized code could lead to unneeded delays.
There are more efficient ways to have lots of things happening at the same time, which we'll get
into in the next chapter,
"2D Graphics and Animation
."

[ Team LiB ]

[ Team LiB ]

Sum It Up: Thread Pools
Now with all this Java thread information, let's create something useful: a thread pool. A thread
pool
is a group of threads designed to execute arbitrary tasks. Perhaps you want to limit the
number of threads used for simultaneous network or I/O connections, or you just want to control
the maximum number of threads on the system for processor-intensive tasks.
The
ThreadPool
class in
Listing 1.1
enables you to choose the number of threads in the pool and to
run tasks defined as Runnables. Here's an example of how to use
ThreadPool
—creating a pool of
eight threads, running a simple task, and then waiting for the task to finish:
ThreadPool myThreadPool = new ThreadPool(8);
myThreadPool.runTask(new Runnable() {
public void run() {
System.out.println("Do something cool here.");
}
});
myThreadPool.join();
The
runTask()
method returns immediately. If all the threads in the pool are busy executing tasks,
calls to
runTask()
will store new tasks in a queue until a thread is available to run it.
Listing 1.1 ThreadPool.java
import java.util.LinkedList;

/**
A thread pool is a group of a limited number of threads that
are used to execute tasks.
*/
public class ThreadPool extends ThreadGroup {

private boolean isAlive;
private LinkedList taskQueue;
private int threadID;
private static int threadPoolID;

/**
Creates a new ThreadPool.
@param numThreads The number of threads in the pool.
*/
public ThreadPool(int numThreads) {
Page
10
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm
super("ThreadPool-" + (threadPoolID++));
setDaemon(true);

isAlive = true;

taskQueue = new LinkedList();
for (int i=0; i<numThreads; i++) {
new PooledThread().start();
}
}


/**
Requests a new task to run. This method returns
immediately, and the task executes on the next available
idle thread in this ThreadPool.
<p>Tasks start execution in the order they are received.
@param task The task to run. If null, no action is taken.
@throws IllegalStateException if this ThreadPool is
already closed.
*/
public synchronized void runTask(Runnable task) {
if (!isAlive) {
throw new IllegalStateException();
}
if (task != null) {
taskQueue.add(task);
notify();
}

}


protected synchronized Runnable getTask()
throws InterruptedException
{
while (taskQueue.size() == 0) {
if (!isAlive) {
return null;
}
wait();
}
return (Runnable)taskQueue.removeFirst();
}


/**
Closes this ThreadPool and returns immediately. All
threads are stopped, and any waiting tasks are not
executed. Once a ThreadPool is closed, no more tasks can
be run on this ThreadPool.
*/
public synchronized void close() {
if (isAlive) {
isAlive = false;
taskQueue.clear();
interrupt();
}
}

Page
11
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm

/**
Closes this ThreadPool and waits for all running threads
to finish. Any waiting tasks are executed.
*/
public void join() {
// notify all waiting threads that this ThreadPool is no
// longer alive
synchronized (this) {
isAlive = false;
notifyAll();
}

// wait for all threads to finish
Thread[] threads = new Thread[activeCount()];
int count = enumerate(threads);
for (int i=0; i<count; i++) {
try {
threads[i].join();
}
catch (InterruptedException ex) { }
}
}


/**
A PooledThread is a Thread in a ThreadPool group,
designed to run tasks (Runnables).
*/
private class PooledThread extends Thread {


public PooledThread() {
super(ThreadPool.this,
"PooledThread-" + (threadID++));
}


public void run() {
while (!isInterrupted()) {

// get a task to run
Runnable task = null;
try {
task = getTask();
}
catch (InterruptedException ex) { }

// if getTask() returned null or was interrupted,
// close this thread by returning.
if (task == null) {
return;
}

// run the task, and eat any exceptions it throws
try {
task.run();
}
catch (Throwable t) {
uncaughtException(this, t);
Page
12
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm
}
}
}
}
}
The only concept the
ThreadPool
class uses that we haven't mentioned yet is use of the
ThreadGroup
class. A
ThreadGroup
is what you'd expect it to be—a group of threads and some
functions to modify the threads. For example, in this code,
ThreadGroup
's
interrupt()
method is
used to stop all waiting threads when the
ThreadPool
is closed.
Now let's test the
ThreadPool
with the
ThreadPoolTest
class, shown in
Listing 1.2
.
ThreadPoolTest
starts a few threads in a
ThreadPool
and also gives the
ThreadPool
several tasks
to run. In this case, each task simply prints a message to the console.
The program takes the number of tasks and the number of threads as arguments. To run the test,
at the command line, enter something like this:
java ThreadPoolTest 8 4
This runs the test with eight tasks and four threads in the thread pool. Of course, you can try any
other combination of tasks and threads you want!
Listing 1.2 ThreadPoolTest.java
public class ThreadPoolTest {

public static void main(String[] args) {
if (args.length != 2) {
System.out.println("Tests the ThreadPool task.");
System.out.println(
"Usage: java ThreadPoolTest numTasks numThreads");
System.out.println(
" numTasks - integer: number of task to run.");
System.out.println(
" numThreads - integer: number of threads " +
"in the thread pool.");
return;
}
int numTasks = Integer.parseInt(args[0]);
int numThreads = Integer.parseInt(args[1]);

// create the thread pool
ThreadPool threadPool = new ThreadPool(numThreads);

// run example tasks
for (int i=0; i<numTasks; i++) {
threadPool.runTask(createTask(i));
}

// close the pool and wait for all tasks to finish.
threadPool.join();
}


/**
Creates a simple Runnable that prints an ID, waits 500
Page
13
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm

milliseconds, then prints the ID again.
*/
private static Runnable createTask(final int taskID) {
return new Runnable() {
public void run() {
System.out.println("Task " + taskID + ": start");

// simulate a long-running task
try {
Thread.sleep(500);
}
catch (InterruptedException ex) { }

System.out.println("Task " + taskID + ": end");
}
};
}
}
Because printing a message to the console takes virtually no time,
ThreadPoolTest
simulates a
longer-running task by sleeping for 500 milliseconds.

[ Team LiB ]

[ Team LiB ]

Summary
That's it for threads! In this chapter, you've learned the basics of how threads work and how to
work with them. Now you can make sure your games don't have thread-synchronization problems
or cause deadlock. You've also learned that you can't avoid dealing with threads in Java games
because all graphical Java applications have at least two threads. Finally, you've created a generic
ThreadPool
class that can be useful in many situations.
[ Team LiB ]

Page
14
of
14
6/14/2010
file://C:\Documents and Settings\deepak\Local Settings\Temp\~hh50EC.htm