java- concurrent programming - synchronization (part 1)
TRANSCRIPT
CONCURRENT PROGRAMMINGSYNCHRONIZATION (PART 1)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 Introduction Thread-safety Race conditions Locking Locking pitfalls
Riccardo Cardin
3Programmazione concorrente e distribuita
INTRODUCTION Threads can reduce development cost and
improve the performance applicationExploiting multiple processors
Improved throughput by utilizing available processorsSimplicity of modeling
Use every thread to do a specific task is simplier than using one thread to do them all
Simplified handling of asynchronous events Prevention of server’s stall while it is fulfilling a request
More reponsive user interfaces Use of different threads for GUI and event management
Event dispatch thread (EDT)
Riccardo Cardin
4Programmazione concorrente e distribuita
INTRODUCTION Risks of threads
Safety hazards Without sufficient synchronization, the ordering of
operations in multiple threads is unpredictable
Riccardo Cardin
public class UnsafeSequence { private int value; /** Returns a unique value. */ public int getNext() { return value++; // Three operations: read, add and store }}
With unlucky timing, two threads could call getNext and receive
the same value
5Programmazione concorrente e distribuita
INTRODUCTION Risks of threads
Liveness hazards An activity gets into a state such that it is permanently unable
to make forward progress
Dining philosophers problem
Performance hazards Poor service time, responsiveness, throughput,resource consumption, or scalability Context switch is not cost free
Riccardo Cardin
If thread A is waiting for a resource that thread B holds exclusively, and B never releases it, A will wait forever.
6Programmazione concorrente e distribuita
INTRODUCTION
Riccardo Cardin
7Programmazione concorrente e distribuita
THREAD SAFETY Writing thread-safe code is about managing
access to shared and mutable state Object state is represented by its dataBy Shared, we mean that a variable could be
accessed by multiple threadsBy mutable, that its value could change
It is far easier to design a class to be thread-safe than to retrofit it later
Riccardo Cardin
Whenever more than a thread accesses a given state variable, and one of them might write to it, they all must coordinate their access to it using synchronization
-- Brian Goetz
8Programmazione concorrente e distribuita
THREAD SAFETY There are three ways to fix a mutable shared
variableDon’t share the state variable across threadsMake the state variable immutableUse synchronization whenever accessing it
Object oriented techniques favor thread safetyEncapsulation ImmutabilityClear specification of invariants
Riccardo Cardin
Stateless objects are always thread-safe.-- Brian Goetz
9Programmazione concorrente e distribuita
THREAD SAFETY
Riccardo Cardin
10Programmazione concorrente e distribuita
RACE CONDITIONS
Race conditionsThe correctness of a computation depends on relative
timing of multiple threads at runtime
Atomicity A set of statements is not atomic if they are not executed in a
single, indivisible operation Read-modifiy-write Check-then-act
Riccardo Cardin
A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment.
-- Brian Goetz
Programmazione concorrente e distribuita
RACE CONDITIONS Read-modify-write race condition
The value of value is read, then modified adding 1 and finally stored into value variable Among the execution of every statement, control flow could
be preempted by another thread
11Riccardo Cardin
public class UnsafeSequence { private int value; /** Returns a unique value. */ public int getNext() { value = value + 1; return value; }}
read value value + 1 store value
Possible preemption
12Programmazione concorrente e distribuita
RACE CONDITIONS Check-then-act race condition
Lazy initialization
The boolean expression depends on a value that is modified according to it
Riccardo Cardin
public class LazyInitRace { private ExpensiveObject instance = null; public ExpensiveObject getInstance() { // Check-then-act if (instance == null) instance = new ExpensiveObject(); return instance; }}
check instance create object store instance
Possible preemption
13Programmazione concorrente e distribuita
RACE CONDITIONS Compound actions
Sequences of operations that must be executed atomically in order to remain thread-safe. Read-modify-write and Check-then-act must always be
atomic to be thread-safeAtomicity is relative to operation that are executed
on shared state The java.util.concurrent.atomic package contains
atomic variable classes for effecting atomic state transitions
Riccardo Cardin
public class SafeSequence { private AtomicInteger value; public int getNext() { return value.incrementAndGet(); // Atomic read-modify-write }}
14Programmazione concorrente e distribuita
RACE CONDITIONS
Riccardo Cardin
15Programmazione concorrente e distribuita
SHARING STATE Writing correct concurrent programs is primarily
about managing access to shared, mutable state It’s all about memory visibility
We want to ensure that when a thread modifies the state of an object, other threads can actually see those changes
If shared state is represented by more than one variable, atomic classes are not useful
Riccardo Cardin
public class UnsafeCachedSequence { private AtomicInteger lastValue; private AtomicInteger value; public int getNext() { // Invariant of the class is not satisfied anymore lastValue.set(value.get()); return value.incrementAndGet(); }}
16Programmazione concorrente e distribuita
LOCKING To preserve state consistency, update related
state variable in a single atomic operation Java has a built-in locking mechanism for enforcing
atomicity: synchronized block
But, it is easier to understand the synchronized keyword after having seen locks in isolation...Riccardo Cardin
synchronized (lock) { // Access or modify shared state guarded by lock}
Object that will serve as lock
Block code to be guarded by the lock
17Programmazione concorrente e distribuita
LOCKING Reentrant locking
Use a Lock to protect a code block
The construct guarantees that only one thread at time can enter the critical section Always release the lock in a finally block to prevents deadlocks The class ReentranctLock implements basic functionalities of a lock
Riccardo Cardin
myLock.lock(); // a ReentrantLock objecttry { // Operation in this block are executed atomically} finally { // make sure the lock is unlocked even if an // exceptions thrown myLock.unlock();}
18Programmazione concorrente e distribuita
LOCKING Reentrant locking
The lock acts as mutual exclusion locksRiccardo Cardin
public class SafeCachedSequence { private Lock lock = new ReentrantLock(); private int lastValue; private int value; public int getNext() { // Invariant of the class is now satisfied lock.lock(); try { lastValue = value; value = value + 1; int result = value; } finally { lock.unlock(); } return result; }}
Now the invariant of the class is
guaranteed by the lock: value and lastValue will
always be updated in a consistent way
19Programmazione concorrente e distribuita
LOCKING Reentrant locking
Riccardo Cardin
Thread 1 Thread 2
getNext getNext
Unsynchronized
Thread 1 Thread 2
getNext
getNext
Synchronized
20Programmazione concorrente e distribuita
LOCKING Reentrant locking
Different threads have to synchronize using the same instance of the lock
It is called reetrant because a thread can repeatedly acquire a lock that it already owns The lock has a hold count that keeps track of the nested calls
to the lock method Prevents deadlocks wrt the subclass mechanism
Every object in Java (since 1.0) has an intrinsic lock The synchronized keyword on a method protects the
access to that method using this reference as lock object All method’s code is guarded
Riccardo Cardin
21Programmazione concorrente e distribuita
LOCKING Intrinsic locking
To call the method, a thread must acquire the intrinsic object lock Static synchronized methods use the Class object as lock.
Riccardo Cardin
public synchronized void method() { // method body}
// ...is equivalent topublic void method() { this.intrinsicLock.lock(); try { // method body } finally { this.intrinsicLock.unlock(); }}
22Programmazione concorrente e distribuita
LOCKING Intrinsic locking suffers of performance issues
Use synchronization by Lock objectOr synchronized block
It uses the reference to an object that will serve as lock
Riccardo Cardin
public class SafeCachedSequence { private Object lock = new Object(); private int lastValue; private int value; public int getNext() { synchronized (lock) { lastValue = value; value = value + 1; int result = value; } return result; }}
23Programmazione concorrente e distribuita
LOCKING
Riccardo Cardin
24Programmazione concorrente e distribuita
LOCKING PITFALLS All the accesses to a mutable shared variable
must be performed with the same lock heldNot only compound actions
Not all data needs to be guarded by a lockOnly mutable data
All the variables involved in the same invariant must be guarded by the same lock It is not sufficient to use intrinsic lock on every
method
Riccardo Cardin
// Not thread-safeif (!vector.contains(element)) vector.add(element);
25Programmazione concorrente e distribuita
LOCKING PITFALLS Poor concurrency
Limits by the availability of processing resources, not by the structure of application itself CPU intensive and I/O operations must be outside
synchronized blocksAcquiring and releasing a lock has some overhead
Not break down synchronized blocks too far
Riccardo Cardin
There is frequently a tension between simplicity and performance. When implementing a synchronization policy, resist the temptation to prematurely sacrifice simplicity (potentially compromising safety) for the sake of performance.
-- Brian Goetz
26Programmazione concorrente e distribuita
EXAMPLES
Riccardo Cardin
https://github.com/rcardin/pcd-snippets
27Programmazione concorrente e distribuita
REFERENCES Chap. 1 «Introduction», Java Concurrency in Practice, Brian Goetz,
2006, Addison-Wesley Professional Chap. 2 «Thread Safety», Java Concurrency in Practice, Brian Goetz,
2006, Addison-Wesley Professional Chap. 3 «Sharing Objects», Java Concurrency in Practice, Brian
Goetz, 2006, Addison-Wesley Professional Dining philosophers problem https://
en.wikipedia.org/wiki/Dining_philosophers_problem Chap. 14 «Multithreading», Core Java Volume I - Fundamentals, Cay
Horstmann, Gary Cornell, 2012, Prentice Hall Intrinsic Locks and Synchronization https://
docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
Riccardo Cardin