Chapter 1
Multithreading
Lecturer: Hồ Tiến Lâm
Contents
Threads Introduction
Interrupting Threads
Thread States
Thread Properties
Synchronization
Callables and Futures
GV. Hồ Tiến Lâm 2
Contents
Threads Introduction
Interrupting Threads
Thread States
Thread Properties
Synchronization
Callables and Futures
GV. Hồ Tiến Lâm 3
Threads Introduction
Multitasking: the ability to have more than one program
working at what seems like the same time.
Programs that can run more than one thread at once are
called mutithreaded programs.
What is the difference between multiple processes and
multiple threads?
GV. Hồ Tiến Lâm 4
Threads Introduction (cont.)
Procedure for running a task in a separate thread:
1. Create a class that implements the Runnable interface and
put the code for doing task into that class:
public interface Runnable {
void run()
}
class MyRunnable implements Runnable {
public void run() {
// put task code here
}
}
GV. Hồ Tiến Lâm 5
Threads Introduction (cont.)
2. Create an object of your class:
Runnable r = new MyRunnable();
3. Create a Thread object from the Runnable:
Thread t = new Thread(r);
4. Start the thread:
[Link]();
GV. Hồ Tiến Lâm 6
Contents
Threads Introduction
Interrupting Threads
Thread States
Thread Properties
Synchronization
Callables and Futures
GV. Hồ Tiến Lâm 7
Interrupting Threads
In JDK 1.0, there was a stop method which is used to
terminate another thread. But it's now deprecated.
Use the interrupt method to request termination of a
thread.
To check if one thread was interrupted:
[Link]().isInterrupted()
If a thread is blocked, it cannot check the interrupted
status => throws InterruptedException
GV. Hồ Tiến Lâm 8
Interrupting Threads (cont.)
public void run() {
try {
…
while (![Link]().isInterrupted()
&& more work to do) {
do more work
}
} catch(InterruptedException e) {
// thread was interrupted during sleep or wait
} finally {
cleanup, if required
}
// exiting the run method terminates the thread
}
The sleep method throws an
InterruptedException if you call it when the
interrupted status is set.
GV. Hồ Tiến Lâm 9
Interrupting Threads (cont.)
public void run() {
try {
…
while (more work to do) {
do more work
[Link](delay);
}
} catch(InterruptedException e) {
// thread was interrupted during sleep or wait
} finally {
cleanup, if required
}
// exiting the run method terminates the thread
}
GV. Hồ Tiến Lâm 10
Contents
Threads Introduction
Interrupting Threads
Thread States
Thread Properties
Synchronization
Callables and Futures
GV. Hồ Tiến Lâm 11
Thread States
There are 4 states:
• New
• Runnable
• Blocked
• Dead
New Threads:
• When you create a thread with new operator, the thread is not
yet running.
GV. Hồ Tiến Lâm 12
Thread States (cont.)
Runnable Threads:
• When you invoke the start method, the thread is runnable.
• Why is the state called “runnable” and not “running”?
A runnable thread may or may not be running at any given
time.
• It is up to the OS to give the thread time to run (time-slicing)
GV. Hồ Tiến Lâm 13
Thread States (cont.)
Blocked Threads:
• The thread goes to sleep by calling the sleep method.
• The thread calls an operation that is blocking on input/output.
• The thread tries to acquire a lock that is currently held by
another thread.
• The thread waits for a condition.
• Calls the suspend method of the thread. However, this
method is deprecated.
GV. Hồ Tiến Lâm 14
Thread States (cont.)
GV. Hồ Tiến Lâm 15
Thread States (cont.)
Dead Threads:
• It dies a natural death because the run method exits normally.
• It dies abruptly because an uncaught exception terminates the
run method.
• To check if a thread is currently alive (runnable or blocked), use
the isAlive method.
• NOTE: You cannot find out if an alive thread is runnable or
blocked, or if a runnable thread is running.
GV. Hồ Tiến Lâm 16
Contents
Threads Introduction
Interrupting Threads
Thread States
Thread Properties
Synchronization
Callables and Futures
GV. Hồ Tiến Lâm 17
Thread Priorities
In Java, every thread has a priority.
You can change the priority of any thread with the
setPriority method.
Range of priority:
• Thread.MIN_PRIORITY: 1
• Thread.NORM_PRIORITY: 5
• Thread.MAX_PRIORITY: 10
Thread priorities are highly system dependent.
GV. Hồ Tiến Lâm 18
Thread Priorities (cont.)
You should never structure your programs so that their
correct functioning depends on priority levels.
If you have several threads with a high priority that rarely
block, the lower-priority threads may never execute.
You cause the executing thread to yield by using
[Link]().. If other runnable threads have a
priority at least as high as the priority of this thread, they
will be scheduled next.
GV. Hồ Tiến Lâm 19
Daemon Threads
You can turn a thread into a daemon thread by calling
[Link](true);
A daemon is simply a thread that has no other role in life
than to serve others.
GV. Hồ Tiến Lâm 20
Thread Groups
This helps you simultaneously work with a group of
threads.
Construct a thread group:
String groupName = ...; // this name must be
unique
ThreadGroup g = new
ThreadGroup(groupName);
Add a thread to the thread group:
Thread t = new Thread(g, threadName);
To check whether any threads of a particular group are
still runnable, use the activeCount method.
GV. Hồ Tiến Lâm 21
Thread Groups (cont.)
To interrupt all threads in a thread group:
[Link](); // g: an object of ThreadGroup
Thread groups can have child subgroups. You can specify
the parent group in the constructor, or by default a newly
created thread group becomes a child of the current thread
group.
Method activeCount and interrupt refer to all
threads in their group and all child groups.
GV. Hồ Tiến Lâm 22
Contents
Threads Introduction
Interrupting Threads
Thread States
Thread Properties
Synchronization
Callables and Futures
GV. Hồ Tiến Lâm 23
Synchronization
What happen if two threads have access to the same object
and each calls a method that modifies the state of the
object?
Depending on the order in which the data were accessed,
corrupted objects can result.
That situation is called a race condition.
GV. Hồ Tiến Lâm 24
An Example of a Race Condition
We simulate a bank with 100 accounts.
We randomly generate transactions that move money
between these accounts.
Each account has one thread.
Each transaction moves a random amount of money from
the account to another random account.
The fact: total amount of money in all accounts does NOT
change whatever we run program for a long time.
LET’S SEE THE DEMO!
GV. Hồ Tiến Lâm 25
An Example of a Race Condition (cont.)
Example 1-3: [Link]
After a few transactions, the total balance still remains at
$100,000 (100 accounts x $1,000).
But after a while, the balance changes slightly.
WHY???
GV. Hồ Tiến Lâm 26
The Race Condition Explained
Reason: two threads are trying to update an account at the
same time.
Suppose two threads simultaneously carry out the
instruction
accounts[to] += amount;
The problem is that these are not atomic operations. The
instruction may be processed as follows:
1. Load accounts[to] into a register.
2. Add amount.
3. Move the result back to accounts[to].
GV. Hồ Tiến Lâm 27
The Race Condition Explained (cont.)
GV. Hồ Tiến Lâm 28
Lock Objects
Outline for protecting a code block with a
ReentrantLock:
[Link](); // a ReentrantLock object
try {
critical section
} finally {
[Link]();
// make sure the lock is unlocked even if
an exception is thrown
}
GV. Hồ Tiến Lâm 29
Lock Objects (cont.)
See the below timeline:
Thread 1 Thread 1
calls finish
transfer executing
Thread 2 Thread 2
calls proceed
transfer→
blocked
GV. Hồ Tiến Lâm 30
Condition Objects
We cannot use code like
if ([Link](from) >= amount)
[Link](from, to, amount);
After passing the condition of this code, this thread may
be deactivated:
if ([Link](from) >= amount)
// thread may be deactivated here
[Link](from, to, amount);
Then the thread is running again, the account balance may
have fallen below the withdrawal amount.
GV. Hồ Tiến Lâm 31
Condition Objects (cont.)
You must make sure that the thread cannot be interrupted
between the test and the insertion:
GV. Hồ Tiến Lâm 32
Condition Objects (cont.)
If there is not enough money in the account → wait until
some other thread has added funds.
But this thread has just gained exclusive access to the
bankLock → no other thread can make a deposit.
Solution: use condition objects.
GV. Hồ Tiến Lâm 33
Condition Objects (cont.)
A lock object can have one or more associated condition
objects.
GV. Hồ Tiến Lâm 34
Condition Objects (cont.)
If the transfer method finds that sufficient funds are not
available, it calls
[Link]();
The current thread is now blocked and gives up the lock.
→ The problem is solved.
Wait set contains all threads waiting for some condition.
Once a thread calls the await method, it enters a wait
set.
GV. Hồ Tiến Lâm 35
Condition Objects (cont.)
When another thread transfer money, then it should call
[Link]();
This call unblocks all threads that are waiting for the
condition.
Then the threads are removed from the wait set.
At this time, the thread should test the condition again.
Because there is no guarantee that the condition is now
fulfilled.
GV. Hồ Tiến Lâm 36
Condition Objects (cont.)
When a thread calls await, it has no way of unblocking
itself.
No thread is left to unblock the others → program hangs:
deadlock situation.
When should you call signalAll?
The rule is to call signalAll whenever the state of an
object changes in a way that might be advantageous to
waiting threads.
GV. Hồ Tiến Lâm 37
Condition Objects (cont.)
signal unblocks only a single thread from the wait set,
chosen at random.
Using condition objects, nothing ever goes wrong. The
total balance stays at $100,000 forever.
Drawback: the program runs a bit slower.
GV. Hồ Tiến Lâm 38
The synchronized Keyword
Summarize the key points about locks and conditions:
• A lock protects sections of code, allowing only one thread to
execute the code at a time.
• A lock manages threads that are trying to enter a protected code
segment.
• A lock can have one or more associated condition objects.
• Each condition object manages threads that have entered a
protected code section but that cannot proceed.
Before the Lock and Condition interfaces were added
to JDK 5.0, Java used a different concurrency mechanism.
GV. Hồ Tiến Lâm 39
The synchronized Keyword (cont.)
Since version 1.0, every object in Java has an implicit
lock.
If a method is declared with the synchronized
keyword → whole code of method is protected by the
object lock.
GV. Hồ Tiến Lâm 40
The synchronized Keyword (cont.)
public synchronized void method() {
method body
}
public void method() {
[Link]();
try {
method body
}
finally { [Link](); }
}
GV. Hồ Tiến Lâm 41
The synchronized Keyword (cont.)
The implicit lock has only one associated condition.
The wait method: adds a thread to the wait set.
The notifyAll/notify methods: unblock waiting
threads.
So, calling wait or notifyAll is the equivalent of
[Link]();
[Link]();
Example: next slide
GV. Hồ Tiến Lâm 42
The synchronized Keyword (cont.)
GV. Hồ Tiến Lâm 43
The synchronized Keyword (cont.)
After changing, this code looks quite shorter.
However, using this mechanism have some limitations:
• You cannot interrupt a thread that is trying to acquire a lock.
• You cannot specify a timeout when trying to acquire a lock.
• Having a single condition per lock can be inefficient.
Using Lock and Condition objects or synchronized
methods depends on your situation.
LET’S SEE THE DEMO!
GV. Hồ Tiến Lâm 44
Synchronized Blocks
Recall that each object has a lock.
A thread can acquire the lock of object in one of two
ways:
1. By calling a synchronized method or
2. By entering a synchronized block.
This is the syntax for a synchronized block:
synchronized (obj) {
critical section
}
GV. Hồ Tiến Lâm 45
Volatile Fields
The volatile keyword offers a lock-free mechanism
for synchronizing access to an instance field.
public synchronized boolean isDone() {
return done;
}
private boolean done;
public boolean isDone() {
return done;
}
private volatile boolean done;
GV. Hồ Tiến Lâm 46
Deadlocks
Example:
• Account 1: $200
• Account 2: $200
• Thread 1: transfer $300 from Account 1 to Account 2
• Thread 2: transfer $400 from Account 2 to Account 1
Result: Both two threads are blocked because the balances
in Account 1 and 2 are not enough.
Such a situation is called a deadlock.
There are other situations that can cause deadlock.
LET’S SEE THE DEMO!
GV. Hồ Tiến Lâm 47
Deadlocks (cont.)
Unfortunately, there’s no way to avoid these deadlocks.
You must design your program to ensure that a deadlock
cannot occur.
GV. Hồ Tiến Lâm 48
Fairness
You can specify that you want a fair locking policy by:
Lock fairLock = new ReentrantLock(true);
A fair lock favors the thread that has been waiting for the
longest time.
But fair lock is a lot slower than regular locks.
Moreover, you have no guarantee that the thread
scheduler is fair. The scheduler may chooses to neglect a
thread that has been waiting a long time for the lock.
GV. Hồ Tiến Lâm 49
Lock Testing and Timeouts
When a thread calls the lock method to acquire a lock
that was owned by another thread, it blocks indefinitely.
The tryLock method:
• Tries to acquire a lock and returns true if it was successful.
• Otherwise, returns false and the thread can do something else.
if ([Link]())
// now the thread owns the lock
try {...}
finally { [Link](); }
else
// do something else
GV. Hồ Tiến Lâm 50
Lock Testing and Timeouts (cont.)
You can call tryLock or await method with a timeout.
Example:
if ([Link](100,
[Link])) …
[Link](100,
[Link]))
The await method returns if another thread has activated
this thread by calling signalAll or signal, or if the
timeout has elapsed, or if the thread was interrupted.
GV. Hồ Tiến Lâm 51
Read/Write Locks
The [Link] package
defines two lock classes: ReentrantLock,
ReentrantReadWriteLock.
The latter is useful when there are many threads that read
from a data structure and fewer threads that modify it.
See the steps to use read/write locks in next slide.
GV. Hồ Tiến Lâm 52
Read/Write Locks (cont.)
1. Construct a ReentrantReadWriteLock object:
private ReentrantReadWriteLock rwl = new
ReentrantReadWriteLock();
2. Extract read and write locks:
private Lock readLock = [Link]();
private Lock writeLock = [Link]();
GV. Hồ Tiến Lâm 53
Read/Write Locks (cont.)
3. Use the read lock in all accessors:
public double getTotalBalance() {
[Link]();
try { . . . }
finally { [Link](); }
}
4. Use the write lock in all mutators:
public void transfer(. . .)
[Link]();
try { . . . }
finally { [Link](); }
}
GV. Hồ Tiến Lâm 54
Callables and Futures
A Callable is similar to a Runnable, but it returns a
value.
public interface Callable<V> {
V call() throws Exception;
}
You use a Future object so that you can start a
computation, give the result to someone, and forget about
it.
public interface Future<V> {
V get() throws …
V get(long timeout, TimeUnit unit) throws …;
void cancel(boolean mayInterrupt);
boolean isCancelled();
boolean isDone();
}
GV. Hồ Tiến Lâm 55
Callables and Futures (cont.)
A call to first get method blocks until the computation is
finished.
The second get throws a TimeoutException if the
call timed out before the computation finished.
If the thread running the computation is interrupted, both
get methods throw an InterruptedException..
If the computation finishes, then get returns immediately.
The isDone method returns false if the computation is
still in progress, true if it is finished.
You can cancel the computation with the cancel
method.
GV. Hồ Tiến Lâm 56
Callables and Futures (cont.)
The FutureTask wrapper is a convenient mechanism.
Example:
Callable<Integer> myComputation = . . .;
FutureTask<Integer> task = new
FutureTask<Integer>(myComputation);
Thread t = new Thread(task); // it's a Runnable
[Link]();
. . .
Integer result = [Link](); // it's a Future
It’s time for the demo!
GV. Hồ Tiến Lâm 57
58 GV. Hồ Tiến Lâm