630 likes | 789 Views
Synchronization. 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
E N D
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