Presentation is loading. Please wait.

Presentation is loading. Please wait.

2006-08-08 Java Threads 11 Threading and Concurrent Programming in Java Synchronization D.W. Denbo Synchronization D.W. Denbo.

Similar presentations


Presentation on theme: "2006-08-08 Java Threads 11 Threading and Concurrent Programming in Java Synchronization D.W. Denbo Synchronization D.W. Denbo."— Presentation transcript:

1 2006-08-08 Java Threads 11 Threading and Concurrent Programming in Java Synchronization D.W. Denbo Synchronization D.W. Denbo

2 2006-08-08Java Threads2 Outline Race condition Lock objects synchronized keyword Synchronized block Volatile Fields Deadlocks Lock testing Race condition Lock objects synchronized keyword Synchronized block Volatile Fields Deadlocks Lock testing

3 2006-08-08Java Threads3 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.

4 2006-08-08Java Threads4 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. 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.

5 2006-08-08Java Threads5 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()); } 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()); }

6 2006-08-08Java Threads6 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) { }

7 2006-08-08Java Threads7 UnsynchBankTest

8 2006-08-08Java Threads8 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!

9 2006-08-08Java Threads9 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?

10 2006-08-08Java Threads10 The instructions might be processed as follows: 1.Load accounts[to] into a register 2.Add amount 3.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. The instructions might be processed as follows: 1.Load accounts[to] into a register 2.Add amount 3.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.

11 Thread 1 Thread 2accounts[to] 5000 Thread 1 registerThread 2 register 5000 5900 5500 5000 5900 5500 load add store load add store

12 2006-08-08Java Threads12 Lock Objects Starting with JDK 5.0, there are two methods for protecting a code block from concurrent access. 1.The synchronized keyword 2.The ReentrantLock class We’ll first take a closer look at the ReentrantLock: Starting with JDK 5.0, there are two methods for protecting a code block from concurrent access. 1.The synchronized keyword 2.The ReentrantLock class We’ll first take a closer look at the ReentrantLock:

13 2006-08-08Java Threads13 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 }

14 2006-08-08Java Threads14 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(); }

15 2006-08-08Java Threads15 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. 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.

16 2006-08-08Java Threads16 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!

17 2006-08-08Java Threads17 public void transfer(int from, int to, double amount) { bankLock.lock(); try { while(accounts[from] < amount) { // wait } // transfer funds } finally { bankLock.unlock(); } So what do we do when there isn’t enough money? We wait until some other thread puts enough money in!

18 2006-08-08Java Threads18 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; }

19 2006-08-08Java Threads19 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.

20 2006-08-08Java Threads20 SynchBankTest

21 2006-08-08Java Threads21 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. 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.

22 2006-08-08Java Threads22 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.

23 2006-08-08Java Threads23 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[]; }

24 2006-08-08Java Threads24 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. 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.

25 2006-08-08Java Threads25 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. 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.

26 2006-08-08Java Threads26 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(); }

27 2006-08-08Java Threads27 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! 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!

28 2006-08-08Java Threads28 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. 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.

29 2006-08-08Java Threads29 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? 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?

30 2006-08-08Java Threads30 SynchBankTest_dl

31 2006-08-08Java Threads31 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. 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.

32 2006-08-08Java Threads32 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. 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.

33 2006-08-08Java Threads33 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.

34 2006-08-08Java Threads34 private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); private Lock readLock = rwl.readLock(); private Lock writeLock = rwl.writeLock(); public double getTotalBalance() { readLock.lock(); try {.... } finally { readLock.unlock(); } public void transfer(...) { writeLock.lock(); try {... } finally { writeLock.unlock(); }

35 2006-08-08Java Threads35 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. 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.

36 2006-08-08Java Threads36 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.

37 2006-08-08Java Threads37 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. 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.


Download ppt "2006-08-08 Java Threads 11 Threading and Concurrent Programming in Java Synchronization D.W. Denbo Synchronization D.W. Denbo."

Similar presentations


Ads by Google