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

Multithreading: Lecturer: Hồ Tiến Lâm

The document discusses multithreading and synchronization in Java. It introduces threads, thread states, and properties. It describes how to create and run threads. Race conditions can occur when multiple threads access shared objects without synchronization. Synchronization is needed to prevent corrupted objects. Lock objects like ReentrantLock can be used to synchronize access to critical sections.

Uploaded by

meocon2010
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
36 views

Multithreading: Lecturer: Hồ Tiến Lâm

The document discusses multithreading and synchronization in Java. It introduces threads, thread states, and properties. It describes how to create and run threads. Race conditions can occur when multiple threads access shared objects without synchronization. Synchronization is needed to prevent corrupted objects. Lock objects like ReentrantLock can be used to synchronize access to critical sections.

Uploaded by

meocon2010
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 58

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:


t.start();

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:
Thread.currentThread().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 (!Thread.currentThread().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
Thread.sleep(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
Thread.yield().. 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
t.setDaemon(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:
g.interrupt(); // 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: UnsynchBankTest.java
 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:

myLock.lock(); // a ReentrantLock object


try {
critical section
} finally {
myLock.unlock();
// 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 (bank.getBalance(from) >= amount)
bank.transfer(from, to, amount);
 After passing the condition of this code, this thread may
be deactivated:
if (bank.getBalance(from) >= amount)
// thread may be deactivated here
bank.transfer(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
sufficientFunds.await();
 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
sufficientFunds.signalAll();
 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() {


implicitLock.lock();
try {
method body
}
finally { implicitLock.unlock(); }
}

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
implicitCondition.await();
implicitCondition.signalAll();
 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 (myLock.tryLock())
// now the thread owns the lock
try {...}
finally { myLock.unlock(); }
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 (myLock.tryLock(100,
TimeUnit.MILLISECONDS)) …

myCondition.await(100,
TimeUnit.MILLISECONDS))

 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 java.util.concurrent.locks 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 = rwl.readLock();
private Lock writeLock = rwl.writeLock();

GV. Hồ Tiến Lâm 53


Read/Write Locks (cont.)
3. Use the read lock in all accessors:
public double getTotalBalance() {
readLock.lock();
try { . . . }
finally { readLock.unlock(); }
}

4. Use the write lock in all mutators:


public void transfer(. . .)
writeLock.lock();
try { . . . }
finally { writeLock.unlock(); }
}
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
t.start();
. . .
Integer result = task.get(); // it's a Future

It’s time for the demo!


GV. Hồ Tiến Lâm 57
58 GV. Hồ Tiến Lâm

You might also like