CONCURRENT PROGRAMMING SYNCHRONIZATION (PART 2) PROGRAMMAZIONE CONCORRENTE E DISTR. Università degli Studi di Padova Dipartimento di Matematica Corso di Laurea in Informatica, A.A. 2015 – 2016 rcardin@math.unipd.it
Programmazione concorrente e distribuita SUMMARY  Conditions  Volatile variables  Atomics  Thread confinement  Immutability 2Riccardo Cardin
Programmazione concorrente e distribuita CONDITIONS  Condition variables  Often a thread enters a critical section only to discover that it can’t proceed A condition is not fulfilled  We can try to use a lock 3Riccardo Cardin if (bank.getBalance(from) >= amount) { // Thread might be deactivated at this point bank.transfer(from, to, amount); } public void transfer(int from, int to, int amount) { bankLock.lock(); try { while (accounts[from] < amount) { // wait } // transfer funds } No thread can withdraw money, due to the acquired lock: DEADLOCK!!
Programmazione concorrente e distribuita CONDITIONS  To avoid unpleasant deadlock, use conditions  A condition variable is built from a lock  A thread owning the lock, calls await on the condition  The lock is released by the thread  Thread is not made runnable when the lock i available. It stays deactivated until the condition will be fulfilled  Wait set for the condition 4Riccardo Cardin class Bank { private Condition sufficientFunds; public Bank() { // Getting a condition with an evocative name sufficientFunds = bankLock.newCondition(); } } sufficientFunds.await();
Programmazione concorrente e distribuita CONDITIONS  When another thread fulfills the condition, it should notify other awaiting threads  One of the awaiting thread will be eligible to acquire the lock and to continue where it left off  Lock must be available  The condition may be fulfilled  Retry to check that condition are met over and over again  An awaiting thread cannot reactive itself: be carefull! 5Riccardo Cardin sufficientFunds.signalAll(); while (!(/* ok to proceed */)) { condition.await(); }
Programmazione concorrente e distribuita CONDITIONS  It’s important that some thread calls the signalAll method eventually  If no other thread bother to reactivate a waiting thread, it will neve run again  DEADLOCK!  Call signalAll whenever the state of an object changes 6Riccardo Cardin public void transfer(int from, int to, int amount) { bankLock.lock(); try { while (accounts[from] < amount) sufficientFunds.await(); // transfer funds sufficientFunds.signalAll(); } finally { bankLock.unlock(); } }
Programmazione concorrente e distribuita CONDITIONS 7Riccardo Cardin
Programmazione concorrente e distribuita CONDITIONS  Intrinsic locks have a single associated condition  The wait method adds a thread to the wait set  The notifyAll method unblocks waiting threads  Having a single condition per intrinsic lock can be inefficient  Which condition has been safisfied? All threads waiting have to be resumed 8Riccardo Cardin public synchronized void transfer(int from, int to, int amount) throws InterruptedException { while (accounts[from] < amount) wait(); // wait on intrinsic object lock // transfer funds notifyAll(); // notify all threads waiting }
Programmazione concorrente e distribuita CONDITIONS PITFALLS  What should you use in your code, Locks or synchronized methods  Neither. In many situation it can be used one of the mechanisms of the java.util.concurrent package  i.e. – Blocking queues  If you have to choose, use synchronized blocks  Use Lock / Condition if you really need the additional power that gives to you  You have to define a custom protocol of synchronization 9Riccardo Cardin Do not underestimate the powers of the dark side of concurrency -- Riccardo Cardin
Programmazione concorrente e distribuita VOLATILE VARIABLES  Cached values and operations reodering are evil!  A volatile variable is not cached by threads  Share the visibility feature of synchronized  Threads will automatically see the most up-to-date value  ...but non of the atomicity features  Possible race-conditions on multiple operations 10Riccardo Cardin If you write a variable which may next be read by another thread, or you read a variable which may have last been written by another thread, you must use synchronization. -- Brian Goetz private volatile boolean done; public boolean isDone() { return done; } public void setDone() { done = true; }
Programmazione concorrente e distribuita VOLATILE VARIABLES  When to use volatile vars instead of locks  Writes do not depend on its current value  DO NOT use for implementing counters!  The variable does not partecipate in invariants with other variables  Slightly better performances 11Riccardo Cardin // Not atomic, you need synchronization public void flipDone() { done = !done; } volatile boolean shutdownRequested; public void shutdown() { shutdownRequested = true; } public void doWork() { while (!shutdownRequested) { // do stuff } } Pattern of use: status flag
Programmazione concorrente e distribuita VOLATILE VARIABLES 12Riccardo Cardin
Programmazione concorrente e distribuita ATOMICS  There are operations other than setter and getter provided by volatile variables  java.util.concurrent.atomic provides classes that guarantee atomicity of other operations  AtomicInteger, AtomicBoolean, AtomicLong, ... 13Riccardo Cardin class AtomicCounter { private AtomicInteger c = new AtomicInteger(0); public void increment() { c.incrementAndGet(); } public void decrement() { c.decrementAndGet(); } public int value() { return c.get(); } } Uses low level CPU operations, that don’t need synchronization (CAS, compare-and-swap)
Programmazione concorrente e distribuita THREAD CONFINEMENT  The best solution to concurrency problems is to not share any mutable state  Use ThreadLocal helper class to give each thread an instance of a class  When thread terminates, value is garbage collected  Do not use as a replacement for global variables  Many JDK classes are not thread-safe  SimpleDateFormat, Random, ... 14Riccardo Cardin public static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>() { protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); }}; String dateStamp = dateFormat.get().format(new Date());
Programmazione concorrente e distribuita IMMUTABILITY  All the problems described so far have to do with accessing shared mutable state  If object state cannot be modified, the risks go away  Immutable object are simple  There are not different states for complex objects  Immutable object are safer  No untrusted code can modify directly object’s state or retain a reference to modify it later  Java does not formally defined immutability  It is not sufficient declaring all fields as final 15Riccardo Cardin Immutable objects are always thread-safe -- Brian Goetz
Programmazione concorrente e distribuita IMMUTABILITY  An object is immutable if:  Its state cannot be modified after construction  So a immutable class has reference only to (effectively) immutable classes  All its fields are final  It is properly constructed  The this reference does not escape during construction, i.e. calling code outside the class, and passing this  Can use mutable state for internal representation  Are this kind of object useful?  There is a big difference between an object been immutbale and the reference to it being immutable 16Riccardo Cardin
Programmazione concorrente e distribuita IMMUTABILITY 17Riccardo Cardin
Programmazione concorrente e distribuita IMMUTABILITY  The final keyword on fields makes possibile the guarantee on initialization safety  A more limited version of the const in C++  No reorder will be done by the compiler  So, final fields can be accessed without additional synchronization  Better maintainability  It’s time to have a look to an immutable class! 18Riccardo Cardin Immutable objects can be used safely by any thread without additional synchronization. -- Brian Goetz
Programmazione concorrente e distribuita IMMUTABILITY 19Riccardo Cardin class OneValueCache { private final BigInteger lastNumber; private final BigInteger[] lastFactors; // Do not use directly a mutable object to construct // an immutable object public OneValueCache(BigInteger i, BigInteger[] factors) { lastNumber = i; lastFactors = Arrays.copyOf(factors, factors.length); } // Do not late ‘escape’ an internal value of the immutable // object. In this way no other code can maliciously modify // that state public BigInteger[] getFactors(BigInteger i) { if (lastNumber == null || !lastNumber.equals(i)) return null; else return Arrays.copyOf(lastFactors, lastFactors.length); } } }
Programmazione concorrente e distribuita EXAMPLES 20Riccardo Cardin https://github.com/rcardin/pcd-snippets
Programmazione concorrente e distribuita REFERENCES  Chap. 14 «Multithreading», Core Java Volume I - Fundamentals, Cay Horstmann, Gary Cornell, 2012, Prentice Hall  Chap. 3 «Sharing Objects», Java Concurrency in Practice, Brian Goetz, 2006, Addison-Wesley Professional  Atomic Access https://docs.oracle.com/javase/tutorial/essential/concurrency/ato mic.html  Java theory and practice: Managing volatility http://www.ibm.com/developerworks/library/j-jtp06197/  Java theory and practice: Going atomic http://www.ibm.com/developerworks/library/j-jtp11234/  What is the difference of Atomic / Volatile / synchronize? http://stackoverflow.com/questions/9749746/what-is-the- difference-of-atomic-volatile-synchronize 21Riccardo Cardin

Java- Concurrent programming - Synchronization (part 2)

  • 1.
    CONCURRENT PROGRAMMING SYNCHRONIZATION (PART2) PROGRAMMAZIONE CONCORRENTE E DISTR. Università degli Studi di Padova Dipartimento di Matematica Corso di Laurea in Informatica, A.A. 2015 – 2016 rcardin@math.unipd.it
  • 2.
    Programmazione concorrente edistribuita SUMMARY  Conditions  Volatile variables  Atomics  Thread confinement  Immutability 2Riccardo Cardin
  • 3.
    Programmazione concorrente edistribuita CONDITIONS  Condition variables  Often a thread enters a critical section only to discover that it can’t proceed A condition is not fulfilled  We can try to use a lock 3Riccardo Cardin if (bank.getBalance(from) >= amount) { // Thread might be deactivated at this point bank.transfer(from, to, amount); } public void transfer(int from, int to, int amount) { bankLock.lock(); try { while (accounts[from] < amount) { // wait } // transfer funds } No thread can withdraw money, due to the acquired lock: DEADLOCK!!
  • 4.
    Programmazione concorrente edistribuita CONDITIONS  To avoid unpleasant deadlock, use conditions  A condition variable is built from a lock  A thread owning the lock, calls await on the condition  The lock is released by the thread  Thread is not made runnable when the lock i available. It stays deactivated until the condition will be fulfilled  Wait set for the condition 4Riccardo Cardin class Bank { private Condition sufficientFunds; public Bank() { // Getting a condition with an evocative name sufficientFunds = bankLock.newCondition(); } } sufficientFunds.await();
  • 5.
    Programmazione concorrente edistribuita CONDITIONS  When another thread fulfills the condition, it should notify other awaiting threads  One of the awaiting thread will be eligible to acquire the lock and to continue where it left off  Lock must be available  The condition may be fulfilled  Retry to check that condition are met over and over again  An awaiting thread cannot reactive itself: be carefull! 5Riccardo Cardin sufficientFunds.signalAll(); while (!(/* ok to proceed */)) { condition.await(); }
  • 6.
    Programmazione concorrente edistribuita CONDITIONS  It’s important that some thread calls the signalAll method eventually  If no other thread bother to reactivate a waiting thread, it will neve run again  DEADLOCK!  Call signalAll whenever the state of an object changes 6Riccardo Cardin public void transfer(int from, int to, int amount) { bankLock.lock(); try { while (accounts[from] < amount) sufficientFunds.await(); // transfer funds sufficientFunds.signalAll(); } finally { bankLock.unlock(); } }
  • 7.
    Programmazione concorrente edistribuita CONDITIONS 7Riccardo Cardin
  • 8.
    Programmazione concorrente edistribuita CONDITIONS  Intrinsic locks have a single associated condition  The wait method adds a thread to the wait set  The notifyAll method unblocks waiting threads  Having a single condition per intrinsic lock can be inefficient  Which condition has been safisfied? All threads waiting have to be resumed 8Riccardo Cardin public synchronized void transfer(int from, int to, int amount) throws InterruptedException { while (accounts[from] < amount) wait(); // wait on intrinsic object lock // transfer funds notifyAll(); // notify all threads waiting }
  • 9.
    Programmazione concorrente edistribuita CONDITIONS PITFALLS  What should you use in your code, Locks or synchronized methods  Neither. In many situation it can be used one of the mechanisms of the java.util.concurrent package  i.e. – Blocking queues  If you have to choose, use synchronized blocks  Use Lock / Condition if you really need the additional power that gives to you  You have to define a custom protocol of synchronization 9Riccardo Cardin Do not underestimate the powers of the dark side of concurrency -- Riccardo Cardin
  • 10.
    Programmazione concorrente edistribuita VOLATILE VARIABLES  Cached values and operations reodering are evil!  A volatile variable is not cached by threads  Share the visibility feature of synchronized  Threads will automatically see the most up-to-date value  ...but non of the atomicity features  Possible race-conditions on multiple operations 10Riccardo Cardin If you write a variable which may next be read by another thread, or you read a variable which may have last been written by another thread, you must use synchronization. -- Brian Goetz private volatile boolean done; public boolean isDone() { return done; } public void setDone() { done = true; }
  • 11.
    Programmazione concorrente edistribuita VOLATILE VARIABLES  When to use volatile vars instead of locks  Writes do not depend on its current value  DO NOT use for implementing counters!  The variable does not partecipate in invariants with other variables  Slightly better performances 11Riccardo Cardin // Not atomic, you need synchronization public void flipDone() { done = !done; } volatile boolean shutdownRequested; public void shutdown() { shutdownRequested = true; } public void doWork() { while (!shutdownRequested) { // do stuff } } Pattern of use: status flag
  • 12.
    Programmazione concorrente edistribuita VOLATILE VARIABLES 12Riccardo Cardin
  • 13.
    Programmazione concorrente edistribuita ATOMICS  There are operations other than setter and getter provided by volatile variables  java.util.concurrent.atomic provides classes that guarantee atomicity of other operations  AtomicInteger, AtomicBoolean, AtomicLong, ... 13Riccardo Cardin class AtomicCounter { private AtomicInteger c = new AtomicInteger(0); public void increment() { c.incrementAndGet(); } public void decrement() { c.decrementAndGet(); } public int value() { return c.get(); } } Uses low level CPU operations, that don’t need synchronization (CAS, compare-and-swap)
  • 14.
    Programmazione concorrente edistribuita THREAD CONFINEMENT  The best solution to concurrency problems is to not share any mutable state  Use ThreadLocal helper class to give each thread an instance of a class  When thread terminates, value is garbage collected  Do not use as a replacement for global variables  Many JDK classes are not thread-safe  SimpleDateFormat, Random, ... 14Riccardo Cardin public static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>() { protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); }}; String dateStamp = dateFormat.get().format(new Date());
  • 15.
    Programmazione concorrente edistribuita IMMUTABILITY  All the problems described so far have to do with accessing shared mutable state  If object state cannot be modified, the risks go away  Immutable object are simple  There are not different states for complex objects  Immutable object are safer  No untrusted code can modify directly object’s state or retain a reference to modify it later  Java does not formally defined immutability  It is not sufficient declaring all fields as final 15Riccardo Cardin Immutable objects are always thread-safe -- Brian Goetz
  • 16.
    Programmazione concorrente edistribuita IMMUTABILITY  An object is immutable if:  Its state cannot be modified after construction  So a immutable class has reference only to (effectively) immutable classes  All its fields are final  It is properly constructed  The this reference does not escape during construction, i.e. calling code outside the class, and passing this  Can use mutable state for internal representation  Are this kind of object useful?  There is a big difference between an object been immutbale and the reference to it being immutable 16Riccardo Cardin
  • 17.
    Programmazione concorrente edistribuita IMMUTABILITY 17Riccardo Cardin
  • 18.
    Programmazione concorrente edistribuita IMMUTABILITY  The final keyword on fields makes possibile the guarantee on initialization safety  A more limited version of the const in C++  No reorder will be done by the compiler  So, final fields can be accessed without additional synchronization  Better maintainability  It’s time to have a look to an immutable class! 18Riccardo Cardin Immutable objects can be used safely by any thread without additional synchronization. -- Brian Goetz
  • 19.
    Programmazione concorrente edistribuita IMMUTABILITY 19Riccardo Cardin class OneValueCache { private final BigInteger lastNumber; private final BigInteger[] lastFactors; // Do not use directly a mutable object to construct // an immutable object public OneValueCache(BigInteger i, BigInteger[] factors) { lastNumber = i; lastFactors = Arrays.copyOf(factors, factors.length); } // Do not late ‘escape’ an internal value of the immutable // object. In this way no other code can maliciously modify // that state public BigInteger[] getFactors(BigInteger i) { if (lastNumber == null || !lastNumber.equals(i)) return null; else return Arrays.copyOf(lastFactors, lastFactors.length); } } }
  • 20.
    Programmazione concorrente edistribuita EXAMPLES 20Riccardo Cardin https://github.com/rcardin/pcd-snippets
  • 21.
    Programmazione concorrente edistribuita REFERENCES  Chap. 14 «Multithreading», Core Java Volume I - Fundamentals, Cay Horstmann, Gary Cornell, 2012, Prentice Hall  Chap. 3 «Sharing Objects», Java Concurrency in Practice, Brian Goetz, 2006, Addison-Wesley Professional  Atomic Access https://docs.oracle.com/javase/tutorial/essential/concurrency/ato mic.html  Java theory and practice: Managing volatility http://www.ibm.com/developerworks/library/j-jtp06197/  Java theory and practice: Going atomic http://www.ibm.com/developerworks/library/j-jtp11234/  What is the difference of Atomic / Volatile / synchronize? http://stackoverflow.com/questions/9749746/what-is-the- difference-of-atomic-volatile-synchronize 21Riccardo Cardin