Title: Race Conditions
1Race Conditions
- When threads share access to a common
object/data, they can conflict with each other
and mess up the consistency of the object/data. - ThreadUnsafeBankDeposit
- Desirable output
- Current balance (d) 0.0, Depositing 100.0, New
balance (d) 100.0 - Current balance (w) 100.0, Withdrawing 100.0,
New balance (w) 0.0 - Current balance (d) 0.0, Depositing 100.0, New
balance (d) 100.0 - Current balance (w) 100.0, Withdrawing 100.0,
New balance (w) 0.0 - Current balance (d) 0.0, Depositing 100.0, New
balance (d) 100.0 - Current balance (d) 100.0, Depositing 100.0, New
balance (d) 200.0 - Current balance (w) 200.0, Withdrawing 100.0,
New balance (w) 100.0 -
- Reality
- Current balance (w) 0.0Current balance (d) 0.0,
New balance (d) 100.0 - , New balance (w) -100.0
2- Current balance (w) 0.0Current balance (d) 0.0,
New balance (d) 100.0 - , New balance (w) -100.0
Deposit thread
Withdraw thread
print(current balance) // balance0 newBalance
balance - 100
Reaches the end ofits time slice
(newBalance-100, balance0)
Gain a time slice
print(current balance)// balance0newBalance
balance100println(new balance) //
newBalance100 balance newBalance // balance100
Gain a time slice
println(new balance) // newBalance-100 balanc
e newBalance // balance-100
3- Current balance (w) 0.0Current balance (d) 0.0,
New balance (d) 100.0 - , New balance (w) -100.0
Deposit thread
Withdraw thread
print(current balance) // balance0 newBalance
balance - 100
Reaches the end ofits time slice
(newBalance-100, balance0)
Gain a time slice
print(current balance)// balance0newBalance
balance100println(new balance) //
newBalance100 balance newBalance // balance100
Gain a time slice
println(new balance) // newBalance-100 balanc
e newBalance // balance-100
newBalance and balance should have been
synchronized.
4- ThreadUnsafeBankAccount2
- Removed a local variable (newBalance) from
ThreadUnsafeBankAccount - to remove a risk to fail data synchronization
between balance and newBalance - Output
- Current balance (d) 0.0, New balance (d) 100.0
- Current balance (w) 100.0, New balance (w) 0.0
- Current balance (d) 0.0, New balance (d) 100.0
- Current balance (w) 100.0, New balance (w) 0.0
- Current balance (d) 0.0Current balance (w) 0.0,
New balance (w) -100.0 - , New balance (d) 100.0
5- Current balance (d) 0.0Current balance (w) 0.0,
New balance (w) -100.0 - , New balance (d) 100.0
Withdraw thread
Deposit thread
print(current balance) // 0 balance100 // --gt
100
Reaches the end ofits time slice (balance0)
Gain a time slice
print(current balance) // 0balance balance
- amount// balance-100println(new balance)
// -100
Gain a time slice
Reaches the end ofits time slice (balance-100)
balance 100 println(new balance)//
balance100
6- Current balance (d) 0.0Current balance (w) 0.0,
New balance (w) -100.0 - , New balance (d) 100.0
Withdraw thread
Deposit thread
print(current balance) // 0 balance100 // --gt
100
Reaches the end ofits time slice (balance0)
Gain a time slice
print(current balance) // 0balance balance
- amount// balance-100println(new balance)
// -100
Gain a time slice
Reaches the end ofits time slice (balance-100)
balance 100 println(new balance)//
balance100
Balance should have been synchronized between
threads.
7- All threads
- Run in their race to complete their tasks.
- Manipulate a shared object/data.
- The end result depends on which of them happens
to win the race. - No guarantees on the order of thread execution.
- No guarantees on the end result on shared data.
8Thread Synchronization
- Synchronizing threads, or synchronizing
object/data access - Serialized/atomic access to a shared object/data
- Atom the smallest possible unit of matter
unable to be broken into separate parts - Atomic code cannot be interrupted during its
execution. Any intermediate result/state cannot
be revealed to other entities. - Atomic a 0 a a 3
9Lock
- Lock
- Used to control the threads that want to
manipulate a shared resource data/object. - java.util.concurrent.locks.Lock interface
- ReentrantLock class most commonly-used lock
class - A lock is added to a class whose methods access a
shared data/object. - Atomic code is surrounded by lock() and unlock()
method calls. - aLock new ReentrantLock()aLock.lock()atomic
code aLock.unlock()
10- When a thread calls lock(),
- it owns the lock until it calls unlock().
- No other threads cannot execute atomic code.
- It is guaranteed to execute all atomic code
before calling unlock(). - If a thread calls lock() when another thread owns
the lock, - it goes to the blocked state.
11Waiting
TimedWaiting
sleep()join()wait()await()
notify()notifyAll()signalAll()interruption
notify()notifyAll()signalAll() interruption
sleep()join()wait()await()
Exits run() or Explicit threadtermination
Runnable
Terminated
new
New
start()
I/O op completionor thread sync done
I/O operation or wait for thread sync (lock)
Blocked
12- The thread scheduler
- Periodically reactivates each blocked thread so
that it can acquire a target lock. - If the lock is still unavailable, the thread is
again blocked. - Notifies the completion of atomic code to waiting
threads. - Choose one of the waiting thread to acquire the
lock. - Eventually, when the target lock is available,
the waiting thread can acquire the lock.
13A Locking Idiom
- Call unlock() in a finally clause.
- aLock new ReentrantLock()aLock.lock()try
atomic code finally aLock.unlock() - If atomic code throws an exception, unlock() is
never called. - A deadlock occurs.
- Atomic code is locked forever, and nobody can
acquire the lock to execute the atomic code.
14ThreadSafeBankAccount
- Output
- Lock obtained
- Current balance (d) 0.0, New balance (d) 100.0
- Lock released
- Lock obtained
- Current balance (w) 100.0, New balance (w) 0.0
- Lock released
- Lock obtained
- Current balance (d) 0.0, New balance (d) 100.0
- Lock released
- Lock obtained
- Current balance (w) 100.0, New balance (w) 0.0
- Lock released
15Nested Locking
- class BankAccount private double
balance private ReentrantLock lock public
void deposit(double amount) lock.lock() bal
ance amount if (balance lt
MIN_BALANCE) subractPenaltyFee() lock.unlock
() private void subractPenaltyFee()
balance - PENALTY
16- class BankAccount private double
balance private ReentrantLock lock public
void deposit(double amount) lock.lock() bala
nce amount notifyCustomer(this) lock.unlo
ck() public void notifyCustomer(BankAccount
account) customer.notify(account) public
double getBalance() return balance - class Customer public void notify(BankAccount
account) System.out.print( account.getBalance()
)
17- class BankAccount private double
balance private ReentrantLock lock public
void deposit(double amount) lock.lock() bal
ance amount if (balance lt
MIN_BALANCE) subractPenaltyFee() lock.unlock
() public void subractPenaltyFee()
lock.lock() balance - PENALTY
lock.unlock()
18- class BankAccount private double
balance private ReentrantLock lock public
void deposit(double amount) System.out.println
(lock.getHoldCount()) lock.lock() balance
amount System.out.println(lock.getHoldCount(
)) if (balance lt MIN_BALANCE) subractPenalty
Fee() lock.unlock() System.out.println(loc
k.getHoldCount()) public void
subractPenaltyFee() lock.lock() System.out.
println(lock.getHoldCount()) - balance - PENALTY lock.unlock()
System.out.println(lock.getHoldCount())
19- class BankAccount private double
balance private ReentrantLock lock public
deposit(double amount) lock.lock() try - balance amount if (balance lt
MIN_BALANCE) subractPenaltyFee() finally
lock.unlock() assert lock.getHoldCount()
0 ERROR public subractPenaltyFee()
balance - PENALTY