0% found this document useful (0 votes)
34 views

Chapter 24 Multithreading: Chapter 16 Applets and Multimedia

The document discusses multithreading in Java. It covers creating task classes that implement the Runnable interface, creating Thread objects to run tasks, and the basic states of a thread - new, runnable, blocked, and dead. Threads allow running multiple tasks concurrently by executing each task on a separate thread. The Thread class is used to create and control threads.

Uploaded by

Nikita Sabale
Copyright
© © All Rights Reserved
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
34 views

Chapter 24 Multithreading: Chapter 16 Applets and Multimedia

The document discusses multithreading in Java. It covers creating task classes that implement the Runnable interface, creating Thread objects to run tasks, and the basic states of a thread - new, runnable, blocked, and dead. Threads allow running multiple tasks concurrently by executing each task on a separate thread. The Thread class is used to create and control threads.

Uploaded by

Nikita Sabale
Copyright
© © All Rights Reserved
Available Formats
Download as PPT, PDF, TXT or read online on Scribd
You are on page 1/ 52

Chapter 24 Multithreading

Chapter 16 Applets and Multimedia

Chapter 24 Multithreading
Chapter 18 Binary I/O

Chapter 25 Networking

Chapter 16 Applets and Multimedia


Chapter 26 Internationalization

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
1
Objectives
 To understand the concept of multithreading and apply it to develop animation (§24.2).
 To develop task classes by implementing the Runnable interface in cases of multiple
inheritance (§24.4).
 To create threads to run tasks using the Thread class (§24.3).
 To control animations using threads (§§24.5, 24.7).
 To run code in the event dispatcher thread (§24.6) .
 To execute tasks in a thread pool (§24.8).
 To use synchronized methods or block to synchronize threads to avoid race conditions
(§24.7.1).
 To synchronize threads using locks (§24.10) .
 To facilitate thread communications using conditions on locks (§§24.11-24.12).
 To use blocking queues to synchronize access to an array queue, linked queue, and
priority queue (§24.13 Optional).
 To restrict number of accesses to a shared resource using semaphores (§24.14 Optional).
 To use the resource ordering technique to avoid deadlock (§24.7.4).
 To understand the life cycle of a thread (§24.16).
 To create synchronized collections using the static methods in the Collections class
(§24.17).
 To display the completion status of a task using JProgressBar (§24.18 Optional).

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
2
Threads Concept
Multiple Thread 1
threads on
Thread 2
multiple
Thread 3
CPUs

Multiple Thread 1
threads
Thread 2
sharing a
Thread 3
single CPU

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
3
Creating Tasks and Threads

java.lang.Runnable TaskClass // Client class


public class Client {
...
// Custom task class public void someMethod() {
public class TaskClass implements Runnable { ...
... // Create an instance of TaskClass
public TaskClass(...) { TaskClass task = new TaskClass(...);
...
} // Create a thread
Thread thread = new Thread(task);
// Implement the run method in Runnable
public void run() { // Start a thread
// Tell system how to run custom thread thread.start();
... ...
} }
... ...
} }

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
4
Example:
Using the Runnabel Interface to
Create and Launch Threads
 Objective: Create and run three threads:
– The first thread prints the letter a 100 times.
– The second thread prints the letter b 100
times.
– The third thread prints the integers 1 through
100.
TaskThreadDemo Run
Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
5
The Thread Class

«interface»
java.lang.Runnable

java.lang.Thread
+Thread() Creates a default thread.
+Thread(task: Runnable) Creates a thread for a specified task.
+start(): void Starts the thread that causes the run() method to be invoked by the JVM.
+isAlive(): boolean Tests whether the thread is currently running.
+setPriority(p: int): void Sets priority p (ranging from 1 to 10) for this thread.
+join(): void Waits for this thread to finish.
+sleep(millis: long): void Puts the runnable object to sleep for a specified time in milliseconds.
+yield(): void Causes this thread to temporarily pause and allow other threads to execute.
+interrupt(): void Interrupts this thread.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
6
Thread States
 A thread can be in one of Four states for threads: new,
runnable, blocked, dead
sleep
done sleeping
suspend blocked
new resume
start
await signal
runnable Wait for lock
Lock available
block on I/O
run exits
stop
I/O complete
dead

Note: suspend, resume,stop deprecated.


Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
7
Thread States
 When a thread has just been created using the new operator, it is in
the new state.

 Once start method is invoked (which calls the run method), the
thread becomes runnable.
 A runnable thread might not be running.
 There can be many runnable threads. But only one of them can be
running at any time point.
 OS decides which thread to run. More on this later.

new
start

runnable

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
8
Thread States
 A runnable thread enters the blocked state when
1. The thread is currently running and method Thread.sleep is called
2. suspend method of the thread is called. (deprecated)
3. The thread calls the await method.
4. The thread tries to lock an object locked by another thread.
5. The thread calls an operation that is blocked on i/o.

sleep

suspend blocked

await

A blocked runnable Wait for lock


thread cannot
be running block on I/O
Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
9
Thread States
 A blocked reenters runnable state when
1. It has slept the specified amount of time.
2. resume method of the thread is called. (deprecated)
3. Another method calls signal or signalAll
4. Object lock released by other thread
5. I/O completed.

done sleeping
blocked
resume

signal
runnable
Lock available
I/O complete

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
10
Thread States
 A runnable thread enters the dead state when
 Its run method exits. Natural death.
 stop method of the thread is called. (deprecated)
 An exception is thrown but not caught.

runnable

run exits
stop
dead

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
11
Thread States
 Finding out states of threads
– Method isAlive allows you to find out whether
a thread is alive or dead.
 This method returns true if the thread is runnable or
blocked,
 false if the thread is still new and not yet runnable or
if the thread is dead
– No way to find out whether an alive thread is
running, runnable, or blocked.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
12
The Static yield() Method
You can use the yield() method to temporarily release time
for other threads. For example, suppose you modify the
code in Lines 57-58 in TaskThreadDemo.java as follows:
public void run() {
for (int i = 1; i <= lastNum; i++) {
System.out.print(" " + i);
Thread.yield();
}
}

Every time a number is printed, the print100 thread is


yielded. So, the numbers are printed after the characters.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
13
The Static sleep(milliseconds) Method
The sleep(long mills) method puts the thread to sleep for the specified
time in milliseconds. For example, suppose you modify the code in
Lines 56-60 in TaskThreadDemo.java as follows:
public void run() {
for (int i = 1; i <= lastNum; i++) {
System.out.print(" " + i);
try {
if (i >= 50) Thread.sleep(1);
}
catch (InterruptedException ex) {
}
}
}

Every time a number (>= 50) is printed, the print100 thread is put to
sleep for 1 millisecond.
Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
14
sleep vs. yield
There is a big difference
– Calling sleep put the current running thread into
the blocked state
– Calling yield does not put the calling thread, t1
into the blocked state
It merely let the scheduler kick in and pick
another thread to run.
It might happen that the t1 is select to run again.
This happens when t1 has a higher priority than
all other runnable threads.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
15
The join() Method
You can use the join() method to force one thread to wait for another thread to
finish. For example, suppose you modify the code in Lines 56-60 in
TaskThreadDemo.java as follows:

public void run(){


Thread thread4 = new Thread(new PrintChar('c', 60));
thread4.start();
try {
for (int i = 1; i < lastNum; i++){
System.out.print(" " + i);
if (i == 50) thread4.join();
}
}
catch (InterruptedException ex) {
}
}
The numbers after 50 are printed after thread4 is finished.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
16
isAlive(), interrupt(), and isInterrupted()
The isAlive() method is used to find out the state of a
thread. It returns true if a thread is in the Ready, Blocked,
or Running state; it returns false if a thread is new and has
not started or if it is finished.

The interrupt() method interrupts a thread in the following


way: If a thread is currently in the Ready or Running state,
its interrupted flag is set; if a thread is currently blocked, it
is awakened and enters the Ready state, and an
java.io.InterruptedException is thrown.

The isInterrupt() method tests whether the thread is


interrupted.
Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
17
Outline
 Introduction: Why and what
 Basics: creating and running threads
 Issues
– Thread states
– Thread scheduling
– Synchronization
– Suspending and stopping threads
 Uses
– Animation
– Threads and Swing
Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
18
Thread Scheduling
At any time, there might be many runnable threads. But only one of
them is actually running.
The thread scheduler decides which runnable thread to run.
Questions:
When does the thread scheduler kick in and pick a thread to run?
How does the thread scheduler select among the runnable
threads?
A not-so-precise answer:
A running Java thread will continue to run until
It calls yield method, or
It ceases to be runnable (dead or blocked), or
Another thread with higher priority moves out of blocked
state
Then the thread scheduler kicks in and picks another thread with
the highest priority to run

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
19
Thread Scheduling
 Two different thread implementations

 “Native thread” implementation (e.g. Windows):


Performs time-slicing. Interrupts the running
thread periodically to give other threads a
chance to run.

 “Green thread” implementation (e.g. Solaris)


Does not perform time-slicing. It keeps a
running thread active until a higher-priority
thread awakes and takes control.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
20
Thread Scheduling
The answer on slide 19 is precise for the green thread
implementation.

For the native thread implementation, the precise answer is


A running Java thread will continue to run until
It calls yield method, or
It ceases to be runnable (dead or blocked), or
Another thread with higher priority moves out of blocked
state, or
It is pre-emptied by OS (time-slicing).

Then the thread scheduler kicks in and picks another thread


with the highest priority to run
Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
21
Thread Priority
 Each thread is assigned a default priority of
Thread.NORM_PRIORITY. You can reset the
priority using setPriority(int priority).

 Some constants for priorities include


Thread.MIN_PRIORITY
Thread.MAX_PRIORITY
Thread.NORM_PRIORITY

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
22
Example: Flashing Text

FlashingText Run

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
23
GUI Event Dispatcher Thread
GUI event handling and painting code executes in a
single thread, called the event dispatcher thread. This
ensures that each event handler finishes executing before
the next one executes and the painting isn’t interrupted by
events.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
24
invokeLater and invokeAndWait
In certain situations, you need to run the code in the event
dispatcher thread to avoid possible deadlock. You can use the
static methods, invokeLater and invokeAndWait, in the
javax.swing.SwingUtilities class to run the code in the event
dispatcher thread. You must put this code in the run method of a
Runnable object and specify the Runnable object as the
argument to invokeLater and invokeAndWait. The invokeLater
method returns immediately, without waiting for the event
dispatcher thread to execute the code. The invokeAndWait
method is just like invokeLater, except that invokeAndWait
doesn't return until the event-dispatching thread has executed the
specified code.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
25
Launch Application from Main Method
So far, you have launched your GUI application from the
main method by creating a frame and making it visible. This
works fine for most applications. In certain situations,
however, it could cause problems. To avoid possible thread
deadlock, you should launch GUI creation from the event
dispatcher thread as follows:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Place the code for creating a frame and setting it properties
}
});
} Run
EventDispatcherThreadDemo

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
26
Case Study: Clock with Audio (Optional)

The example creates an applet that displays a running clock and


announces the time at one-minute intervals. For example, if the
current time is 6:30:00, the applet announces, "six o’clock thirty
minutes a.m." If the current time is 20:20:00, the applet announces,
"eight o’clock twenty minutes p.m." Also add a label to display the
digital time.
ClockWithAudio Run

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
27
Run Audio on Separate Thread
When you run the preceding program, you will notice that the second
hand does not display at the first, second, and third seconds of the
minute. This is because sleep(1500) is invoked twice in the
announceTime() method, which takes three seconds to announce the
time at the beginning of each minute. Thus, the next action event is
delayed for three seconds during the first three seconds of each
minute. As a result of this delay, the time is not updated and the clock
was not repainted for these three seconds. To fix this problem, you
should announce the time on a separate thread. This can be
accomplished by modifying the announceTime method.

ClockWithAudioOnSeparateThread Run

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
28
Thread Pools
Starting a new thread for each task could limit throughput and cause
poor performance. A thread pool is ideal to manage the number of
tasks executing concurrently. JDK 1.5 uses the Executor interface for
executing tasks in a thread pool and the ExecutorService interface for
managing and controlling tasks. ExecutorService is a subinterface of
Executor.
«interface»
java.util.concurrent.Executor
+execute(Runnable object): void Executes the runnable task.
\
«interface»
java.util.concurrent.ExecutorService
+shutdown(): void Shuts down the executor, but allows the tasks in the executor to
complete. Once shutdown, it cannot accept new tasks.
+shutdownNow(): List<Runnable> Shuts down the executor immediately even though there are
unfinished threads in the pool. Returns a list of unfinished
tasks.
+isShutdown(): boolean Returns true if the executor has been shutdown.
+isTerminated(): boolean Returns true if all tasks in the pool are terminated.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
29
Creating Executors
To create an Executor object, use the static methods in the Executors
class.

java.util.concurrent.Executors
+newFixedThreadPool(numberOfThreads: Creates a thread pool with a fixed number of threads executing
int): ExecutorService concurrently. A thread may be reused to execute another task
after its current task is finished.
+newCachedThreadPool(): Creates a thread pool that creates new threads as needed, but
ExecutorService will reuse previously constructed threads when they are
available.

ExecutorDemo Run

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
30
Thread Synchronization

A shared resource may be corrupted if it is


accessed simultaneously by multiple threads. For
example, two unsynchronized threads accessing
the same bank account may cause conflict.

Step balance thread[i] thread[j]

1 0 newBalance = bank.getBalance() + 1;
2 0 newBalance = bank.getBalance() + 1;
3 1 bank.setBalance(newBalance);
4 1 bank.setBalance(newBalance);

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
31
Example: Showing Resource Conflict
 Objective: Write a program that demonstrates the problem of
resource conflict. Suppose that you create and launch one
hundred threads, each of which adds a penny to an account.
Assume that the account is initially empty.
java.lang.Runnable
-char token
100 1 1 1
AddAPennyTask
+getToken AccountWithoutSync Account
+setToken
+paintComponet -bank: Account -balance: int
+mouseClicked
+run(): void -thread: Thread[]
+getBalance(): int
+deposit(amount: int): void
+main(args: String[]): void

AccountWithoutSync

Run
Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
32
Race Condition
What, then, caused the error in the example? Here is a possible scenario:

Step balance Task 1 Task 2

1 0 newBalance = balance + 1;
2 0 newBalance = balance + 1;
3 1 balance = newBalance;
4 1 balance = newBalance;
);

The effect of this scenario is that Task 1 did nothing, because in


Step 4 Task 2 overrides Task 1's result. Obviously, the problem is
that Task 1 and Task 2 are accessing a common resource in a way
that causes conflict. This is a common problem known as a race
condition in multithreaded programs. A class is said to be thread-
safe if an object of the class does not cause a race condition in the
presence of multiple threads. As demonstrated in the preceding
example, the Account class is not thread-safe.
Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
33
The synchronized keyword
To avoid resource conflicts, it is necessary to prevent more than one
thread from simultaneously entering certain part of the program,
known as critical region. The critical region in the Listing 24.7 is the
entire deposit method. You can use the synchronized keyword to
synchronize the method so that only one thread can access the method
at a time. There are several ways to correct the problem in Listing
24.7, one approach is to make Account thread-safe by adding the
synchronized keyword in the deposit method in Line 45 as follows:

public synchronized void deposit(double amount)

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
34
Synchronizing Instance Methods and
Static Methods
A synchronized method acquires a lock before it executes.
In the case of an instance method, the lock is on the object
for which the method was invoked. In the case of a static
method, the lock is on the class. If one thread invokes a
synchronized instance method (respectively, static method)
on an object, the lock of that object (respectively, class) is
acquired first, then the method is executed, and finally the
lock is released. Another thread invoking the same method
of that object (respectively, class) is blocked until the lock
is released.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
35
Synchronizing Instance Methods and
Static Methods
With the deposit method synchronized, the preceding scenario cannot
happen. If Task 2 starts to enter the method, and Task 1 is already in
the method, Task 2 is blocked until Task 1 finishes the method.

Task 1 Task 2

Acquire a-char
locktoken
on the object account -char token

+getToken +getToken
-char token +setToken +setToken
+paintComponet +paintComponet
Execute
+getToken the deposit method
+mouseClicked +mouseClicked
+setToken
+paintComponet Wait to acquire the lock
-char token
+mouseClicked
-char token
+getToken Release the lock
+setToken
+getToken
+paintComponet
-char token Acqurie a lock on the object account
+setToken
+mouseClicked
+paintComponet
+getToken -char token
+mouseClicked
+setToken
+paintComponet Execute the deposit method
+getToken
+mouseClicked +setToken
+paintComponet
-char token
+mouseClicked
+getToken Release the lock
+setToken
+paintComponet

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
36
Synchronizing Statements
Invoking a synchronized instance method of an object acquires a lock
on the object, and invoking a synchronized static method of a class
acquires a lock on the class. A synchronized statement can be used to
acquire a lock on any object, not just this object, when executing a
block of the code in a method. This block is referred to as a
synchronized block. The general form of a synchronized statement is
as follows:
synchronized (expr) {
statements;
}

The expression expr must evaluate to an object reference. If the object


is already locked by another thread, the thread is blocked until the
lock is released. When a lock is obtained on the object, the statements
in the synchronized block are executed, and then the lock is released.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
37
Synchronizing Statements vs. Methods
Any synchronized instance method can be converted into a
synchronized statement. Suppose that the following is a synchronized
instance method:

public synchronized void xMethod() {


// method body
}

This method is equivalent to

public void xMethod() {


synchronized (this) {
// method body
}
}

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
38
Synchronization Using Locks
A synchronized instance method implicitly acquires a lock on the
instance before it executes the method.
JDK 1.5 enables you to use locks explicitly. The new locking features
are flexible and give you more control for coordinating threads. A
lock is an instance of the Lock interface, which declares the methods
for acquiring and releasing locks, as shown in Figure below. A lock
may also use the newCondition() method to create any number of
Condition objects, which can be used for thread communications.
«interface»
java.util.concurrent.locks.Lock
+lock(): void Acquires the lock.
+unlock(): void Releases the lock.
+newCondition(): Condition Returns a new Condition instance that is bound to this
Lock instance.

java.util.concurrent.locks.ReentrantLock
+ReentrantLock() Same as ReentrantLock(false).
+ReentrantLock(fair: boolean) Creates a lock with the given fairness policy. When the
fairness is true, the longest-waiting thread will get the
lock. Otherwise, there is no particular access order.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
39
Fairness Policy
ReentrantLock is a concrete implementation of Lock for
creating mutual exclusive locks. You can create a lock with
the specified fairness policy. True fairness policies
guarantee the longest-wait thread to obtain the lock first.
False fairness policies grant a lock to a waiting thread
without any access order. Programs using fair locks
accessed by many threads may have poor overall
performance than those using the default setting, but have
smaller variances in times to obtain locks and guarantee
lack of starvation.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
40
Example: Using Locks
This example revises AccountWithoutSync.java in Listing
24.7 to synchronize the account modification using explicit
locks.

AccountWithSyncUsingLock

Run

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
41
Cooperation Among Threads
The conditions can be used to facilitate communications among
threads. A thread can specify what to do under a certain condition.
Conditions are objects created by invoking the newCondition()
method on a Lock object. Once a condition is created, you can use its
await(), signal(), and signalAll() methods for thread communications,
as shown in Figure below. The await() method causes the current
thread to wait until the condition is signaled. The signal() method
wakes up one waiting thread, and the signalAll() method wakes all
waiting threads.

«interface»
java.util.concurrent.Condition
+await(): void Causes the current thread to wait until the condition is signaled.
+signal(): void Wakes up one waiting thread.
+signalAll(): Condition Wakes up all waiting threads.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
42
Example: Thread Cooperation
Write a program that demonstrates thread cooperation. Suppose that
you create and launch two threads, one deposits to an account, and
the other withdraws from the same account. The second thread has to
wait if the amount to be withdrawn is more than the current balance
in the account. Whenever new fund is deposited to the account, the
first thread notifies the second thread to resume. If the amount is still
not enough for a withdrawal, the second thread has to continue to
wait for more fund in the account. Assume the initial balance is 0 and
the amount to deposit and to withdraw is randomly generated.

ThreadCooperation

Run

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
43
Cooperation Among Threads
To synchronize the operations, use a lock with a condition:
newDeposit (i.e., new deposit added to the account). If the balance is
less than the amount to be withdrawn, the withdraw task will wait
for the newDeposit condition. When the deposit task adds money to
the account, the task signals the waiting withdraw task to try again.
The interaction between the two tasks is shown in Figure below.

Withdraw Task Deposit Task

-char token -char token


lock.lock(); lock.lock();
+getToken +getToken
+setToken
-char token +setToken
-char token
+paintComponet +paintComponet
while (balance < withdrawAmount) balance += depositAmount
+mouseClicked
+mouseClicked
+getToken +getToken
newDeposit.await();
+setToken +setToken
+paintComponet +paintComponet
-char token
newDeposit.signalAll();
+mouseClicked
+mouseClicked
balance -= withdrawAmount
+getToken
-char token +setToken
lock.unlock();
+paintComponet
lock.unlock(); +mouseClicked
+getToken
-char token
+setToken
Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
44
Condition Object
Often, a thread enters a critical section, only to discover that it
can’t proceed until a condition is fulfilled. JDK5.0 uses a condition
object to manage threads that have acquired a lock but cannot do
useful work.
For example, what do we do where there is not enough money in
the account? We wait until some other thread has added funds. But
this thread has just gained exclusive access to the lock, so no other
thread has a chance to make a deposit. This is where condition
object come in.
A lock object can have one or more associated condition objects.
You obtain a condition object with the newCondition method. It
is customary to give each condition object a name that evokes the
condition that it represents. For example:
Condition newDeposit = lock.newCondition();

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
45
Condition Object
If the transfer method finds that sufficient funds are not available, it
calls newDeposit.await();
The current thread is now blocked and gives up the lock. This lets in
another thread that can (possibly) increase the account balance.
When another thread transfers money, it should call
newDeposit.signalAll();
to unblock all threads that are waiting for the condition.
or call newDeposit.signa();
to unblock a single thread from the wait set, chosen at random.
When the threads are removed from the wait set, they are again
runnable and the scheduler will eventually activate them again.
At that time, they will attempt to reenter the object. As soon as
the lock is available, one of them will acquire the lock and
continue where it left off, returning from the await. At this time
the thread should test the condition again. There is no guarantee
that the condition is now fulfilled.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
46
Condition Object
 It is crucial that some other thread calls the signalAll
eventually. When a thread calls await, it has no way of
unblocking itself. It puts its faith in the other thread. If none of
them bother to unblock the waiting thread, it will never run again.
This can lead to deadlock situation.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
47
Case Study: Producer/Consumer
Consider the classic Consumer/Producer example. Suppose you use a buffer to
store integers. The buffer size is limited. The buffer provides the method write(int)
to add an int value to the buffer and the method read() to read and delete an int
value from the buffer. To synchronize the operations, use a lock with two
conditions: notEmpty (i.e., buffer is not empty) and notFull (i.e., buffer is not full).
When a task adds an int to the buffer, if the buffer is full, the task will wait for the
notFull condition. When a task deletes an int from the buffer, if the buffer is empty,
the task will wait for the notEmpty condition. The interaction between the two
tasks is shown in Figure below.

Task for adding an int Task for deleting an int

-char token -char token

while (count == CAPACITY)


+getToken while (count == 0)
+getToken
+setToken
notFull.await(); +setToken
notEmpty.await();
+paintComponet +paintComponet
+mouseClicked
-char token +mouseClicked
-char token

+getToken +getToken
Delete an int to the buffer
Add an int to the buffer
+setToken +setToken
+paintComponet +paintComponet
-char token
-char token
+mouseClicked +mouseClicked
+getToken +getToken
notEmpty.signal(); notFull.signal();
+setToken +setToken
+paintComponet +paintComponet
-char token -char token
Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
48
Case Study: Producer/Consumer (Optional)
Listing 24.10 presents the complete program. The program contains
the Buffer class (lines 43-89) and two tasks for repeatedly producing
and consuming numbers to and from the buffer (lines 15-41). The
write(int) method (line 58) adds an integer to the buffer. The read()
method (line 75) deletes and returns an integer from the buffer.

For simplicity, the buffer is implemented using a linked list (lines 48-
49). Two conditions notEmpty and notFull on the lock are created in
lines 55-56. The conditions are bound to a lock. A lock must be
acquired before a condition can be applied.

ConsumerProducer Run

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
49
Deadlock
The Dining-Philosophers’ Problem

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
50
Deadlock
Sometimes two or more threads need to acquire the locks on several shared objects.
This could cause deadlock, in which each thread has the lock on one of the objects
and is waiting for the lock on the other object. Consider the scenario with two
threads and two objects, as shown in Figure below. Thread 1 acquired a lock on
object1 and Thread 2 acquired a lock on object2. Now Thread 1 is waiting for the
lock on object2 and Thread 2 for the lock on object1. The two threads wait for each
other to release the in order to get the lock, and neither can continue to run.
Step Thread 1 Thread 2

1 synchronized (object1) {
2 synchronized (object2) {
3 // do something here
4 // do something here
5 synchronized (object2) {
6 synchronized (object1) {
// do something here // do something here
} }
} }

Wait for Thread 2 to Wait for Thread 1 to


release the lock on object2 release the lock on object1

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
51
Preventing Deadlock
Deadlock can be easily avoided by using a simple technique known
as resource ordering. With this technique, you assign an order on all
the objects whose locks must be acquired and ensure that each
thread acquires the locks in that order. For the example in Figure in
last slide, suppose the objects are ordered as object1 and object2.
Using the resource ordering technique, Thread 2 must acquire a lock
on object1 first, then on object2. Once Thread 1 acquired a lock on
object1, Thread 2 has to wait for a lock on object1. So Thread 1 will
be able to acquire a lock on object2 and no deadlock would occur.

Liang, Introduction to Java Programming, Sixth Edition, (c) 2005 Pearson Education, Inc. All
rights reserved. 0-13-148952-6
52

You might also like