# Presentation: 182755

## Threading and ConcurrentProgramming in Java

- Synchronization
- D.W. Denbo

- Java Threads

- 2006-08-08

## Outline

- Race condition
- Lock objects
- synchronized keyword
- Synchronized block
- Volatile Fields
- Deadlocks
- Lock testing

- Java Threads

- 2006-08-08

## Race Condition

- In most real applications, two or more threads will need to share access to the same objects.  What happens if two threads have access to the same object calls a methods that changes the object state?  As you might expect the threads can step on each other’s toes.  Such a situation is often called a *race condition*.

- Java Threads

- 2006-08-08

## Example of a Race Condition

- To avoid corruption of share data, you must learn how to *synchronize the access*.
- In this example, we have the class Bank with the method transfer.  Money can be transferred between accounts.  A thread is created for each account to transfer money from its account to another.

- Java Threads

- 2006-08-08

**public void transfer(int from, int to, double amount) {**
**	****System.out.print(Thread.currentThread());**
**	****accounts[from] -= amount;**
**	****System.out.printf(“%10.2f from %d to $d”,amount,from,to);**
**	****accounts[to]+= amount;**
**	****System.out.printf(“Total: %10.2f%n”,getTotalBalance());**
**}**

- Java Threads

- 2006-08-08

## public void run() {

**public void run() {**
**	****try {**
**	****	****int toAccount = (int)(bank.size()*Math.random());**
**	****	****double amount = maxAmount*Math.random();**
**	****	****bank.transfer(fromAccount, toAccount, amount);**
**	****	****Thread.sleep((int)(DELAY*Math.random()));**
**	****} catch (InterruptedException ie) {**
**	****}**
**}**

- Java Threads

- 2006-08-08

## UnsynchBankTest

- Java Threads

- 2006-08-08

- While this simulation is running, we don’t know how much money is in any one account.  We do, however, know that the total amount of money should remain constant!

- Java Threads

- 2006-08-08

## Errors have crept in and some amount of money was either lost or spontaneously created.  Why?

accounts[to] += amount;

The problem is that these are not atomic operations!

- Errors have crept in and some amount of money was either lost or spontaneously created.  Why?
**accounts[to] += amount;**
- The problem is that these are not atomic operations!

*What Happened?*

- Java Threads

- 2006-08-08

- The instructions might be processed as follows:
- Load accounts[to] into a register
- Add amount
- Move the result back to accounts[to].
- If the first thread executes Steps 1 & 2, then is interrupted by a second thread that updates the same entry, the second threads changes are lost.

- Java Threads

- 2006-08-08

## 5000

- Thread 2

- accounts[to]

- Thread 1 register

- Thread 2 register

- 5900

- 5500

- 5500

- 5900

- 5900

- 5500

- load

- add

- store

- load

- add

- store

- Java Threads

- 2006-08-08

## Lock Objects

- Starting with JDK 5.0, there are two methods for protecting a code block from concurrent access.
- The synchronized keyword
- The ReentrantLock class
- We’ll first take a closer look at the ReentrantLock:

- Java Threads

- 2006-08-08

- This construct guarantees that only one thread can access the critical section at a time.

**myLock.lock(); // a ReentrantLock object**
**try {**
**	****// critical section**
**} finally {**
**	****myLock.unlock();  // make sure lock is unlocked**
**}**

- Java Threads

- 2006-08-08

## public class Bank {

**public class Bank {**
**	****public void transfer(int from, int to, double amount) {**
**	****	****bankLock.lock();**
**	****	****try {**
**	****	****	****if(accounts[from] < amount) return;**
**	****	****	****System.out.print(Thread.currentThread());**
**	****	****	****accounts[from] -= amount;**
**	****	****	****System.out.printf(“%10.2f from %d to %d”,amount,from,to);**
**	****	****	****accounts[to] += amount;**
**	****	****	****System.out.printf(“Total: %10.2f%n”,getTotalBalance());**
**	****	****} finally {**
**	****	****	****bankLock.unlock();**
**	****	****}**
**	****}**
**	****....**
**	****// Reentrant lock implements the Lock interface**
**	****private Lock bankLock = new ReentrantLock();**
**}**

- Java Threads

- 2006-08-08

- Note that
- Each Bank object has its own ReentrankLock
- If two threads try to access the same Bank object, then the lock will serialize access.
- If two threads try to access different Bank objects, each thread acquires a different lock and neither thread is blocked.

- Java Threads

- 2006-08-08

## Condition Objects

*Condition Objects*

- Often, a thread enters a critical section, only to discover that it can’t proceed until a condition is fulfilled.  You use a condition object to manage threads that have acquired lock but cannot do useful work.  Lets extend our example to cover the case of insufficient funds.

**if(bank.getBalance(from) >= amount)**
**	****bank.transfer(from, to, amount);**

- The above won’t work!

- Java Threads

- 2006-08-08

## So what do we do when there isn’t enough money?  We wait until some other thread puts enough money in!

**public void transfer(int from, int to, double amount) {**
**	****bankLock.lock();**
**	****try {**
**	****	****while(accounts[from] < amount) {**
**	****	****	****// wait**
**	****	****}**
**	****	****// transfer funds**
**	****} finally {**
**	****	****bankLock.unlock();**
**	****}**
**}**

- Java Threads

- 2006-08-08

- A lock object can have one or more associated condition objects.  Here we set up a condition object to represent the “sufficient funds” condition.

**class Bank {**
**	****public Bank() {**
**	****	****....**
**	****	****sufficientFunds = bankLock.newCondition();**
**	****}**
**	****....**
**	****private Condition sufficientFunds;**
**}**

- Java Threads

- 2006-08-08

## NOTE: the call to signalAll does not immediately activate a waiting thread.  It only unblocks the waiting threads so that they can compete for entry into the object.

**public void transfer(int from, int to, double amount) {**
**	****bankLock.lock();**
**	****try {**
**	****	****while(accounts[from] < amount) **
**	****	****	****sufficientFunds.await();**
**	****	****// transfer funds**
**	****	****...**
**	****	****sufficientFunds.signalAll();**
**	****} finally {**
**	****	****bankLock.unlock();**
**	****}**
**}**

- NOTE: the call to signalAll does not immediately activate a waiting thread.  It only unblocks the waiting threads so that they can compete for entry into the object.

- Java Threads

- 2006-08-08

## SynchBankTest

- Java Threads

- 2006-08-08

- A lock protects sections of code, allowing only one thread access at a time.
- A lock manages threads that are trying to enter protected code segments.
- A lock can have one more associated condition objects.
- Each condition object manages threads that have entered a protected code section but cannot proceed.

- Java Threads

- 2006-08-08

## synchronized Keyword

- Every object in Java has an  implicit lock.  If a method is declared with the synchronized keyword, then the object’s lock protects the entire method.  This implicit lock has a single implicit condition.  The wait method adds a thread to the wait set, and the notifyAll/notify methods unblock the waiting threads.

- Java Threads

- 2006-08-08

## class Bank {

**class Bank {**
**	****public **_**synchronized**_** void transfer(int from, int to, double amount) {**
**	****	****while(accounts[from] < amount) **
**	****	****	**_**wait**_**(); // wait on objects lock’s single condition**
**	****	****accounts[from] -= amount;**
**	****	****accounts[to] += amount;**
**	****	**_**notifyAll**_**(); // notify all threads waiting on the condition**
**	****}**
**	****public synchronized double getTotalBalance() {....}**
**	****private double accounts[];**
**}**

- Java Threads

- 2006-08-08

- While using synchronized yields more concise code, implicit locks and conditions have some limitations.
- Cannot interrupt a thread that is trying to acquire a lock
- Cannot specify a timeout when trying to acquire a lock
- Having a single condition per lock can be inefficient
- The virtual machine locking primitives do not map well to the most efficient locking mechanisms available in hardware.

- Java Threads

- 2006-08-08

- Core Java authors recommendations
- Best to use neither Lock/Condition or the synchronized keyword.  Should first see if java.util.concurrent package offers a solution.
- If the synchronized keyword works for your solution, you should use it.  You write less code and have less room for error.
- Use Lock/Condition if you specifically need the additional power that these constructs give you.

- Java Threads

- 2006-08-08

## Synchronized Blocks

*Synchronized Blocks*

- If you deal with legacy code (or legacy programmers :-), you need to know something about the built-in synchronization primitives.  Recall each object has a lock.

**class Bank {**
**	****public void transfer(int from, int to, double amount) {**
**	****	****synchronized(lock) {  // an ad-hoc lock**
**	****	****	****accounts[from] -= amount;**
**	****	****	****accounts[to] += amount;**
**	****	****}**
**	****}**
**	****private double accounts[];**
**	****private Object lock = new Object();**
**}**

- Java Threads

- 2006-08-08

## Volatile Fields

- Computers with multiple processors can temporarily hold memory values in registers or local memory caches.  Threads running in different processors may see different values for the same memory location!
- Compilers can reorder instructions for maximum throughput.  Compilers won’t change the meaning of the code, but will assume that all changes occur within the block of optimized code.  However, a memory value can be changed by another thread!

- Java Threads

- 2006-08-08

- Concurrent access to a field is safe in these three conditions:
- The field is volatile
- The field is final, and it is accessed after the constructor has completed.
- The field access is protected by a lock
- NOTE: Prior to JDK 5.0, the semantics of volatile were rather permissive.

- Java Threads

- 2006-08-08

## Deadlocks

- Locks and conditions cannot solve all problems that might arise in multithreading.  Consider ...
- Account 1: $200
- Account 2: $300
- Thread 1: Transfer $300 from Account 1 to 2
- Thread 2: Transfer $400 from Account 2 to 1.
- In the example, deadlocks can’t occur because each transfer is limited to $1000.  With 100 acounts and $100,000 total, at least on account must have $1000.  What if we change this restriction?

- Java Threads

- 2006-08-08

## SynchBankTest_dl

- Java Threads

- 2006-08-08

## Creating Deadlocks

- You can create a deadlock by making the i’th thread responsible for putting money into the i’th account, rather than for taking it out of the i’th account.  It becomes possible for all the threads to gang up on one account, each trying to remove more money that it contains.
- Another deadlock situation: Change the signalAll method to signal in the SynchBankTest program.  It deadlocks because it is now only unblocking a single thread, if that thread can’t proceed...
- Unfortunately, there is nothing in the Java language to avoid or break these deadlocks.

- Java Threads

- 2006-08-08

## Lock Testing and Timeouts

- A thread blocks indefinitely when it calls the lock method to acquire a lock that is owned by another thread.  Other things you can try:
- tryLock boolean method.  Returns true if lock acquired.
- tryLock(100, TimeUnit.MILLISECONDS), with a timeout.  tryLock can be unfair and grab the lock without waiting its turn, with the timeout tryLock is fair.
- myCondition.await(1000, TimeUnit.MICROSECONDS), will return if notifyAll has been called by another thread, or if the timeout has elapsed.

- Java Threads

- 2006-08-08

## Read/Write Locks

- java.util.concurrent.locks package defines two lock classes, ReentrantLock and ReentrantReadWriteLock.  The latter is advantageous if many threads read and only a few write.

- Java Threads

- 2006-08-08

## private ReentrantReadWriteLock rwl = 

**private ReentrantReadWriteLock rwl = **
**                          ****new ReentrantReadWriteLock();**
**private Lock readLock = rwl.readLock();**
**private Lock writeLock = rwl.writeLock();**
**public double getTotalBalance() {**
**	****readLock.lock();**
**	****try {  .... **
**	****} finally {**
**	****	****readLock.unlock();**
**	****}**
**}****_x0010_**
**public void transfer(...) {**
**	****writeLock.lock();**
**	****try { ...**
**	****} finally {**
**	****	****writeLock.unlock();**
**	****}**
**}****_x0010__x0010_**

- Java Threads

- 2006-08-08

## Why the stop and suspend Methods are Deprecated

- JDK 1.0 defined a stop method that simply terminates a thread, and a suspend method that blocks a thread.
- Both of these methods have been deprecated since JDK 1.2.  The stop method is inherently unsafe, and experience has shown that the suspend method can lead to deadlocks.

- Java Threads

- 2006-08-08

## stop method

- This method terminates all pending methods, including the run method.  When a thread is stopped, it immediately gives up the locks on all objects that it has locked.  This can leave objects in an inconsistent state.  For example, suppose a TransferThread is stopped in the middle of moving money from one account to another, after the withdrawal and before the deposit?  Now the Bank object is damaged.

- Java Threads

- 2006-08-08

## suspend Method

- Unlike stop, suspend won’t damage objects.  However, if you suspend a thread that owns a lock, then the lock is unavailable until the thread is resumed.  If the thread that calls the suspend method tries to acquire the same lock, the program deadlocks.  This situation occurs frequently in GUIs.
- If you want to suspend a thread, introduce a variable and test it in a safe place of your run method.

- Java Threads

- 2006-08-08