java- concurrent programming - synchronization (part 2)
TRANSCRIPT
CONCURRENT PROGRAMMINGSYNCHRONIZATION (PART 2)PROGRAMMAZIONE CONCORRENTE E DISTR.Università degli Studi di Padova
Dipartimento di Matematica
Corso di Laurea in Informatica, A.A. 2015 – [email protected]
2Programmazione concorrente e distribuita
SUMMARY Conditions Volatile variables Atomics Thread confinement Immutability
Riccardo Cardin
3Programmazione concorrente e distribuita
CONDITIONS Condition variables
Often a thread enters a critical section only to discover that it can’t proceedA condition is not fulfilled
We can try to use a lock
Riccardo 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!!
4Programmazione 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
Riccardo Cardin
class Bank { private Condition sufficientFunds; public Bank() { // Getting a condition with an evocative name sufficientFunds = bankLock.newCondition(); }}
sufficientFunds.await();
5Programmazione 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!
Riccardo Cardin
sufficientFunds.signalAll();
while (!(/* ok to proceed */)) { condition.await();}
6Programmazione 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
Riccardo 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(); } }
7Programmazione concorrente e distribuita
CONDITIONS
Riccardo Cardin
8Programmazione concorrente e distribuita
CONDITIONS Intrinsic locks have a single associated condition
The wait method adds a thread to the wait setThe 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 resumedRiccardo 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}
9Programmazione concorrente e distribuita
CONDITIONS PITFALLS What should you use in your code, Locks or synchronized methodsNeither. 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 blocksUse Lock / Condition if you really need the
additional power that gives to you You have to define a custom protocol of synchronization
Riccardo Cardin
Do not underestimate the powers of the dark side of concurrency-- Riccardo Cardin
10Programmazione 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
Riccardo 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; }
11Programmazione 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 variablesSlightly better performances
Riccardo Cardin
// Not atomic, you need synchronizationpublic void flipDone() { done = !done; }
volatile boolean shutdownRequested;public void shutdown() { shutdownRequested = true; }public void doWork() { while (!shutdownRequested) { // do stuff }}
Pattern of use: status
flag
12Programmazione concorrente e distribuita
VOLATILE VARIABLES
Riccardo Cardin
13Programmazione 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, ...
Riccardo 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)
14Programmazione concorrente e distribuita
THREAD CONFINEMENT The best solution to concurrency problems is to
not share any mutable stateUse 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, ...
Riccardo 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());
15Programmazione 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
Riccardo Cardin
Immutable objects are always thread-safe-- Brian Goetz
16Programmazione 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 classesAll 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
Riccardo Cardin
17Programmazione concorrente e distribuita
IMMUTABILITY
Riccardo Cardin
18Programmazione concorrente e distribuita
IMMUTABILITY
The final keyword on fields makes possibile the guarantee on initialization safetyA more limited version of the const in C++No reorder will be done by the compilerSo, final fields can be accessed without additional
synchronizationBetter maintainability
It’s time to have a look to an immutable class!Riccardo Cardin
Immutable objects can be used safely by any thread without additional synchronization.
-- Brian Goetz
19Programmazione concorrente e distribuita
IMMUTABILITY
Riccardo 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); } }}
20Programmazione concorrente e distribuita
EXAMPLES
Riccardo Cardin
https://github.com/rcardin/pcd-snippets
21Programmazione 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/atomic.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
Riccardo Cardin