To check if one thread was interrupted: Thread.currentThread.isInterruptedThread.currentThread.isInterrupted If a thread is blocked, it cannot check the interrupted status => throws Int
Trang 1Chapter 1 Multithreading
Lecturer: Hồ Tiến Lâm
Trang 4Threads 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?
multiple threads?
Trang 5Threads 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() }
5
}
class MyRunnable implements Runnable {
public void run() {
// put task code here }
}
GV Hồ Tiến Lâm
Trang 6Threads 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();
Trang 8Interrupting 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()Thread.currentThread().isInterrupted()
If a thread is blocked, it cannot check the interrupted
status => throws InterruptedException
Trang 9Interrupting Threads (cont.)
public void run() {
// thread was interrupted during sleep or wait
The sleep method throws an
InterruptedException if you call it when the
interrupted status is set
GV Hồ Tiến Lâm
Trang 10Interrupting Threads (cont.)
public void run() {
// thread was interrupted during sleep or wait } finally {
cleanup, if required
}
Trang 13Thread 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
Trang 14Thread 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.
• The thread waits for a condition.
• Calls the suspend method of the thread However, this
method is deprecated.
Trang 15Thread States (cont.)
15
GV Hồ Tiến Lâm
Trang 16Thread 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.
the isAlive method.
• NOTE: You cannot find out if an alive thread is runnable or
blocked, or if a runnable thread is running.
Trang 18Thread Priorities
In Java, every thread has a priority
You can change the priority of any thread with the
Trang 19Thread 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
If other runnable threads have a
Thread.yield() If other runnable threads have a
priority at least as high as the priority of this thread, they will be scheduled next
19
GV Hồ Tiến Lâm
Trang 21Thread 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
21
GV Hồ Tiến Lâm
Trang 22Thread 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
Trang 24That situation is called a race condition.
That situation is called a race condition.
Trang 25An 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
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
25
GV Hồ Tiến Lâm
LET’S SEE THE DEMO!
Trang 26An Example of a Race Condition (cont.)
Trang 27The 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
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].
27
GV Hồ Tiến Lâm
Trang 28The Race Condition Explained (cont.)
Trang 30Lock Objects (cont.)
See the below timeline:
Thread 1
calls
transfer
Thread 1 finish executing
Trang 31Condition 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
31
GV Hồ Tiến Lâm
Trang 32Condition Objects (cont.)
You must make sure that the thread cannot be interrupted between the test and the insertion:
Trang 33Condition 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.
33
GV Hồ Tiến Lâm
Trang 34Condition Objects (cont.)
A lock object can have one or more associated condition objects
Trang 35Condition 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.
Wait set contains all threads waiting for some condition.
Once a thread calls the await method, it enters a wait
set
35
GV Hồ Tiến Lâm
Trang 36Condition 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
Trang 37Condition 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
37
GV Hồ Tiến Lâm
Trang 38Condition 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.
Trang 39The 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.
• 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
39
GV Hồ Tiến Lâm
Trang 40The 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
Trang 41The synchronized Keyword (cont.)
Trang 42The 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
So, calling wait or notifyAll is the equivalent of
implicitCondition.await();
implicitCondition.signalAll();
Example: next slide
Trang 43The synchronized Keyword (cont.)
43
GV Hồ Tiến Lâm
Trang 44The 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.
Trang 45Synchronized 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:
45
GV Hồ Tiến Lâm
synchronized (obj) {
critical section }
Trang 46private boolean done;
public boolean isDone() {
Trang 47Example:
• 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
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
47
GV Hồ Tiến Lâm
LET’S SEE THE DEMO!
Trang 48Deadlocks (cont.)
Unfortunately, there’s no way to avoid these deadlocks
You must design your program to ensure that a deadlock cannot occur
Trang 49You 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
49
GV Hồ Tiến Lâm
Trang 50Lock 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.
// now the thread owns the lock
try { }
Trang 51Lock Testing and Timeouts (cont.)
You can call tryLock or await method with a timeout
51
GV Hồ Tiến Lâm
myCondition.await(100,
TimeUnit.MILLISECONDS))
Trang 52Read/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
See the steps to use read/write locks in next slide
Trang 53Read/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();
53
GV Hồ Tiến Lâm
Trang 54Read/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( .)
Trang 55Callables 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 FutureFuture object so that you can start a
computation, give the result to someone, and forget about it
public interface Future<V> {
Trang 56Callables 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
Trang 57Callables and Futures (cont.)
The FutureTask wrapper is a convenient mechanism
It’s time for the demo!
Thread t = new Thread(task); // it's a Runnable
t.start();
.
Integer result = task.get(); // it's a Future