Synchronization
E N D
Presentation Transcript
Overview • synchronization mechanisms in modern RTEs • concurrency issues • places where synchronization is needed • structural ways (design patterns) for exclusive access
Overview • synchronization mechanism in Java RTE • Visibility and re-ordering • Design patterns to avoid safety issues: • monitor pattern. • client side locking. • class composition. • version iterattor.
Java Synchronization - concurrent objects safety • threads which access the same object concurrently. • safety - synchronize access to internal state of the object
if threads can access internal state of object concurrently - not safe • @invariant is not guaranteed • code perfectly safe in sequential environment
Visibility and Reordering – unsafe constructs in concurrent execution • Visibility - when threads see values written to memory by other threads • Reordering - compiler / RTE change code to optimize it
anonymous class - class that has no name • combines class declaration and instance creation in one step in-line • allows "on the fly" creation of object • reduce the number of .java files necessary • class used in specific situation: Comparator • compiler will create separate class files: ClassName$SomeNumber.class
Inlining • Inline expansion - compiler optimization that replaces a function call site with the body of the callee. • improve time and space usage at runtime, at cost of binary file size
output = 0 • thread t does not "see" the change to the state of d performed in main thread • thread main - implicitly created by JVM • executes main() method • main calls d.set(10): 10 is written to memory: i_ member of: VisibilityDemo object • t reads from i_ (d.get() ) • Java does not guarantee t sees most recent value written to this memory location
Re-ordering • compiler must be able to re-order simple instructions to optimize our code
Re-ordering • compiler guarantees safe reordering in non-concurrent execution environments. • order of operations is that the sequence will end with operation 4
Re-ordering • in concurrent environments, reordering may harm
“must-happen-before” • compiler would not reorder if "must-happen-before" constraint
“must-happen-before” • "must-happen-before“ - call to any (non-inline) function • compiler would not go recursively into that function
"synchronized" construct in Java • allow only one thread at a time to enter a specific method of an object • synchronized keyword to method's declaration
synchronized • Java coordinates actions of threads on object: • keyword before method name in class definition: • public synchronized int add() - only one thread is allowed to enter • constructors cannot be synchronized - syntax error (only thread that creates an object access its constructor)
synchronized • Java RTE ensures that only one thread access this method. • solves visibility and reordering problems; • "write" to memory during synchronized code section is guaranteed to be returned to all "read" operations following it
How "synchronized" is implemented? • Java mechanism - use it better / avoid common pitfalls • each object inside JVM (at runtime) has a lock ("monitor") • JVM maintain/initialize locks. • cannot access locks explicitly • access implicitly using synchronized
locks • locks are in one of two states; • in possession of thread • available • thread T tries to acquire the lock of any object. • if available – lock transferred to T possession • otherwise, T sleeps (queue) until lock available • T wakes up and tries to acquire lock
synchronized • each thread, calling the method, must first acquire lock. • when thread exits – thread releases lock
The cost of locks – time, concurrency • memory sync.: after thread exits – memory of all threads synchronize with main memory • thread may cache copies of memory in its own memory (e.g., CPU registers / CPU cache) • blocking: threads must wait for each other
When to Use Synchronization • mutable variable accessible from different threads must be protected with lock • else, you may be hit by re-ordering problems • monitor pattern - internal state of object is encapsulated. • objects are responsible to synchronize access to state: synchronized get() /set()
When to Use Synchronization • invariant involving several members - synchronized with same lock. • never lock large parts of code. • minimize code sections which use locking
Synchronized Properties • synchronized keyword is not part of the method signature. • synchronized keyword cannot be specified in an interface. • constructors cannot be synchronized • no point - as long as constructor is not complete, object instance is not accessible to other threads, unless… • static method as synchronized - lock associated with the class to be used • (each class in Java is also an object on its own) • Java locks are Reentrant: same thread holding the lock can get it again and again.
Statics • Access to static fields protected via synchronized static methods and blocks. Static synchronization employs the lock possessed by the Class object • static lock for class C can also be accessed inside instance methods via: synchronized(C.class) { /* body */ }
Locks are Reentrant/Recursive • thread, T, acquired the lock of Even object • in add() , T will be able to enter doSomething() - T already possesses lock of same object.
synchronized instance methods in subclasses employ the same lock as in their superclasses • synchronization in an inner class method is independent of its outer class
Locks are Reentrant/Recursive • Reentrant locks are implemented using counter • same thread may acquire lock multiple time, consecutively, without releasing • each time the lock is acquired, an internal counter is incremented. • lock is unavailable whenever counter > 1. • when thread releases the lock, the counter value is decremented by 1. • when counter reaches 0, the lock is then available
Locking a Specific Object • synchronized keyword to method declaration • implicitly uses the lock of current object • explicitly request to lock a specific object we wish to acquire • not advised to use synchronized blocks. It is usually better to define synchronized methods
Vector: addIfAbsent() • addIfAbsent() • new class – Vector hold some information • javadoc - Vector class is thread-safe • add an element only if missing • Is it thread safe?
incorrect solution • lock protecting addIfAbsent() may be different from lock protecting add() • not sure that add() is synchronized • implementation of Vector may change - Vector can become not thread safe
Design Patterns to Enforce Safety • Composition / Client Side Locking
Composition / Containment • "almost" reimplementing the functionality of Vector. Why not extend Vector class and add the function we want? • do not know how the class Vector protects itself from concurrent access. • do not know/not have access to, which objects are used for synchronized access • good design strategy to have a basic (non thread safe) object and a thread safe version of it.
Composition / Containment • wrapper around Vector class: • Enforces right synchronization policy • Delegates all calls (after synchronization is verified) to underlying implementation class.
Composition / Containment • we know exactly which lock is used to synchronize access to our vector. • best applied in situations where: • we are not sure/ do not know the internal implementation of an object • implementation of object may change without our knowledge
all methods are synchronized. • no public fields or encapsulation violations. • methods are finite (no infinite loops or unbounded recursion) • all fields are initialized to a consistent state in constructors. • state of object is consistent
Client Side Locking • we may know the identity of the object which is used for synchronization • Vector class uses its own monitor (lock) to achieve synchronization
Client side locking • only when we know internal implementation • Vector uses monitor • not when unknown internal implementation • not when implementation may change
Client side locking • not OO: • responsibility of synchronization to clients instead of centralizing it in object • cannot ensure consistency among ALL clients : • If client does not synchronize correctly, then ALL the code will behave incorrectly. • better to enforce safety on provider side
Version Iterators • Iteratorsand Generics • casting is bad - introduces clutter • programmer knows what kind of data • run time error – if wrong cast
Generics • programmers express intent • restrict a list to contain a particular data type