Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Java Monitor Objects: Synchronization (Part 1) Douglas C. Schmidt [email protected] www.dre.vanderbilt.edu/~schmidt Institute for Software Integrated Systems Vanderbilt University Nashville, Tennessee, USA Learning Objectives in this Part of the Lesson • Recognize the synchronized methods/statements provided by Java build-in monitor objects to support mutual exclusion Producer Monitor Object offer() <<contains>> poll() synchronized m1() synchronized m2() 1 Wait Queue 1 Consumer <<contains>> Entrance Queue Mutual exclusion is used to protect shared state from 2 access by multiple threads corruption due to concurrent Java Synchronized Methods 3 Java Synchronized Methods • The BusySynchronizedQueue class BusySynchronizedQueue<E> implements BoundedQueue<E> { class showcases Java built-in private LinkedList<E> mList; synchronization mechanisms private int mCapacity; BusySynchronizedQueue(int capacity) { mList = new LinkedList<E>(); mCapacity = capacity; } ... See github.com/douglascraigschmidt/POSA/tree/ 4 master/ex/M3/Queues/BusySynchronizedQueue Java Synchronized Methods • The BusySynchronizedQueue class BusySynchronizedQueue<E> implements BoundedQueue<E> { class showcases Java built-in private LinkedList<E> mList; synchronization mechanisms private int mCapacity; BusySynchronizedQueue(int capacity){ mList = new LinkedList<E>(); mCapacity = capacity; } ... 5 Java Synchronized Methods • The BusySynchronizedQueue class BusySynchronizedQueue<E> implements BoundedQueue<E> { class showcases Java built-in private LinkedList<E> mList; synchronization mechanisms private int mCapacity; This internal state must be protected against race conditions BusySynchronizedQueue(int capacity){ mList = new LinkedList<E>(); mCapacity = capacity; } ... 6 Java Synchronized Methods • The BusySynchronizedQueue class BusySynchronizedQueue<E> implements BoundedQueue<E> { class showcases Java built-in private LinkedList<E> mList; synchronization mechanisms private int mCapacity; BusySynchronizedQueue(int capacity){ mList = new LinkedList<E>(); mCapacity = capacity; } ... The constructor initializes the internal state 7 Java Synchronized Methods • Methods in a built-in monitor class BusySynchronizedQueue<E> implements BoundedQueue<E> { object can be marked with ... the synchronized keyword public synchronized boolean offer(E e) { ... } public synchronized E poll() { ... } public synchronized boolean isEmpty() { ... } ... See docs.oracle.com/javase/tutorial/ 8 essential/concurrency/syncmeth.html Java Synchronized Methods • Methods in a built-in monitor class BusySynchronizedQueue<E> implements BoundedQueue<E> { object can be marked with ... the synchronized keyword public synchronized boolean • A synchronized method offer(E e) is serialized wrt any other { ... } synchronized method in public synchronized E poll() an object { ... } public synchronized boolean isEmpty() { ... } ... See lesson on “Java 9 ReentrantLock” Java Synchronized Methods • Methods in a built-in monitor class BusySynchronizedQueue<E> implements BoundedQueue<E> { object can be marked with ... the synchronized keyword public synchronized boolean • A synchronized method offer(E e) is serialized wrt any other { if (!isFull()) { mList.add(e); synchronized method in return true; an object } else • When used in the method return false; declaration, the entire body } of the method is serialized public synchronized E poll() { return mList.poll(); } public synchronized boolean isEmpty() { return mList.size() == 0; } ... 10 Java Synchronized Methods • The synchronized keyword is not considered to be part of a method's signature class BusySynchronizedQueue<E> implements BoundedQueue<E> { ... public synchronized boolean offer(E e) { ... } public synchronized E poll() { ... } Synchronization is considered to be an “implementation detail” public synchronized boolean isEmpty() { … } ... See gee.cs.oswego.edu/dl/cpj/ 11 mechanics.html#synchronization Java Synchronized Methods class SynchronizedQueue<E> • The synchronized keyword extends BusySynchronizedQueue<E>{ is not considered to be part ... of a method's signature public boolean offer(E e) • synchronized is not inherited { ... } when subclasses override public E poll() superclass methods { ... } These methods will not be synchronized unless the implementation explicitly synchronizes them public boolean isEmpty() { ... } ... 12 Java Synchronized Methods • Pros • Synchronized methods can be identified by examining the method interfaces • The syntax is compact • i.e., the code is more legible • The “method” is the unit of synchronization • Cons • Synchronizes to the “intrinsic lock” (this), so it is possible for other objects to synchronize with it too • The granularity of locking is “coarse-grained” • i.e., locking is a a perobject/per-method basis See stackoverflow.com/questions/574240/is-there-an-advantage-to-use13 a-synchronized-method-instead-of-a-synchronized-blo/574525#574525 End of Java Monitor Objects: Synchronization (Part 1) 14 Java Monitor Objects: Synchronization (Part 2) Douglas C. Schmidt [email protected] www.dre.vanderbilt.edu/~schmidt Institute for Software Integrated Systems Vanderbilt University Nashville, Tennessee, USA Learning Objectives in this Part of the Lesson • Recognize the synchronized methods/statements provided by Java build-in monitor objects to support mutual exclusion Producer Monitor Object offer() <<contains>> poll() m1() m2() 1 Wait Queue 1 Consumer <<contains>> Entrance Queue void m1() { synchronized(this) { ... } } Mutual exclusion is used to protect shared state from 2 access by multiple threads corruption due to concurrent Java Synchronized Statements 3 Java Synchronized Statements • Synchronized methods incur several constraints 4 Java Synchronized Statements • Synchronized methods incur several constraints, e.g. • They can yield excessive overhead due to coarsegrained serialization Thread2 Thread1 m1() m2() Synchronized A Java Queue Monitor Object synchronized m1() synchronized m2() <<contains>> Synchronization occurs at the method level 1 Wait Queue wait() notify() notifyAll() 5 <<contains>> 1 Entrance Queue Java Synchronized Statements • Synchronized methods incur several constraints, e.g. • They can yield excessive overhead due to coarsegrained serialization • Always synchronizes on the “implicit lock” (this) Thread2 Thread1 m1() m2() Synchronized A Java Queue Monitor Object synchronized m1() synchronized m2() May be a source of contention <<contains>> 1 Wait Queue wait() notify() notifyAll() 6 <<contains>> 1 Entrance Queue Java Synchronized Statements • e.g., consider the Java Exchanger class public class Exchanger<V> { ... private synchronized void createSlot(int index){ final Slot newSlot = new Slot(); final Slot[] a = arena; if (a[index] == null) a[index] = newSlot; } Defines a synchronization point where threads can pair & swap elements within pairs private volatile Slot[] arena = new Slot[CAPACITY]; See docs.oracle.com/javase/8/docs/api/ 7 java/util/concurrent/Exchanger.html Java Synchronized Statements • e.g., consider the Java Exchanger class • One approach synchronizes at the method level public class Exchanger<V> { ... private synchronized void createSlot(int index){ final Slot newSlot = new Slot(); final Slot[] a = arena; if (a[index] == null) a[index] = newSlot; } private volatile Slot[] arena = new Slot[CAPACITY]; 8 Java Synchronized Statements • e.g., consider the Java Exchanger class • One approach synchronizes at the method level Lazily create slot if this is the first time it’s accessed public class Exchanger<V> { ... private synchronized void createSlot(int index){ final Slot newSlot = new Slot(); final Slot[] a = arena; if (a[index] == null) a[index] = newSlot; } private volatile Slot[] arena = new Slot[CAPACITY]; 9 Java Synchronized Statements public class Exchanger<V> { • e.g., consider the Java ... Exchanger class private • One approach synchronizes void createSlot(int index){ at the method level final Slot newSlot = new Slot(); final Slot[] a = arena; • Another approach synchronizes synchronized (this) { individual statements if (a[index] == null) a[index] = newSlot; } } private volatile Slot[] arena = new Slot[CAPACITY]; See docs.oracle.com/javase/tutorial/ 10 essential/concurrency/locksync.html Java Synchronized Statements public class Exchanger<V> { • e.g., consider the Java ... Exchanger class private • One approach synchronizes void createSlot(int index){ at the method level final Slot newSlot = new Slot(); final Slot[] a = arena; • Another approach synchronizes synchronized (this) { individual statements if (a[index] == null) a[index] = newSlot; } } Synchronized statements are “finer-grained” than synchronized methods private volatile Slot[] arena = new Slot[CAPACITY]; 11 Java Synchronized Statements public class Exchanger<V> { • e.g., consider the Java ... Exchanger class private • One approach synchronizes void createSlot(int index){ at the method level final Slot newSlot = new Slot(); final Slot[] a = arena; • Another approach synchronizes synchronized (this) { individual statements if (a[index] == null) a[index] = newSlot; } } Create slot outside of lock to narrow the synchronization region private volatile Slot[] arena = new Slot[CAPACITY]; 12 Java Synchronized Statements public class Exchanger<V> { • e.g., consider the Java ... Exchanger class private • One approach synchronizes void createSlot(int index){ at the method level final Slot newSlot = new Slot(); final Slot[] a = arena; • Another approach synchronizes synchronized (this) { individual statements if (a[index] == null) • “Intrinsic lock” is often used a[index] = newSlot; to synchronize a statement } } Only this statement is serialized via the “intrinsic lock” private volatile Slot[] arena = new Slot[CAPACITY]; 13 Java Synchronized Statements public class Exchanger<V> { • e.g., consider the Java ... Exchanger class private • One approach synchronizes void createSlot(int index){ at the method level final Slot newSlot = new Slot(); final Slot[] a = arena; • Another approach synchronizes synchronized (a) { individual statements if (a[index] == null) • “Intrinsic lock” is often used a[index] = newSlot; to synchronize a statement } • “Explicit lock” synchronization } can also be used Can also synchronize using an explicit object private volatile Slot[] arena = new Slot[CAPACITY]; 14 Java Synchronized Statements public class Exchanger<V> { • e.g., consider the Java ... Exchanger class private • One approach synchronizes void createSlot(int index){ at the method level final Slot newSlot = new Slot(); final Slot[] a = arena; • Another approach synchronizes synchronized (a) { individual statements if (a[index] == null) • “Intrinsic lock” is often used a[index] = newSlot; to synchronize a statement } • “Explicit lock” synchronization } can also be used Can also synchronize using an explicit object • e.g., in situations where the intrinsic lock is too limited or too contended private volatile Slot[] arena = new Slot[CAPACITY]; See www.dre.vanderbilt.edu/~schmidt/ 15 PDF/specific-notification.pdf Java Synchronized Statements • More info is available in the online Java documentation See docs.oracle.com/javase/tutorial/ 16 essential/concurrency/locksync.html Java Synchronized Statements • Pros • Allows a private field to be used as the synchronizer • i.e., “hides” implementation details • Synchronized statements can be found by searching references to a variable via the IDE • Cons • The syntax is more complicated • i.e., code is harder to read See stackoverflow.com/questions/574240/is-there-an-advantage-to-use17 a-synchronized-method-instead-of-a-synchronized-blo/574525#574525 Implementing the Double-Checked Locking Pattern 18 Implementing the Double-Checked Locking Pattern public class Exchanger<V> { • Synchronized statements can ... be used to implement patterns private void createSlot(int index){ like Double-Checked Locking final Slot newSlot = new Slot(); final Slot[] a = arena; synchronized (a) { if (a[index] == null) a[index] = newSlot; } } private Object doExchange(...) { ... final Slot slot = arena[index]; if (slot == null) // Lazily initialize slots createSlot(index); private volatile Slot[] arena = new Slot[CAPACITY]; See en.wikipedia.org/wiki/ 19 Double-checked_locking Implementing the Double-Checked Locking Pattern public class Exchanger<V> { • Synchronized statements can ... be used to implement patterns private void createSlot(int index){ like Double-Checked Locking final Slot newSlot = new Slot(); • Synchronization is done final Slot[] a = arena; “lazily” when initialization synchronized (a) { if (a[index] == null) is first performed a[index] = newSlot; } } private Object doExchange(...) { ... final Slot slot = arena[index]; if (slot == null) // Lazily initialize slots createSlot(index); private volatile Slot[] arena = new Slot[CAPACITY]; 20 Implementing the Double-Checked Locking Pattern public class Exchanger<V> { • Synchronized statements can ... be used to implement patterns private void createSlot(int index){ like Double-Checked Locking final Slot newSlot = new Slot(); • Synchronization is done final Slot[] a = arena; “lazily” when initialization synchronized (a) { if (a[index] == null) is first performed a[index] = newSlot; } } Double-Checked Locking optimization is done here private Object doExchange(...) { ... final Slot slot = arena[index]; if (slot == null) // Lazily initialize slots createSlot(index); private volatile Slot[] arena = new Slot[CAPACITY]; 21 Implementing the Double-Checked Locking Pattern public class Exchanger<V> { • Synchronized statements can ... be used to implement patterns private void createSlot(int index){ like Double-Checked Locking final Slot newSlot = new Slot(); • Synchronization is done final Slot[] a = arena; “lazily” when initialization synchronized (a) { if (a[index] == null) is first performed a[index] = newSlot; } } Only create a slot if the current slot is null private Object doExchange(...) { ... final Slot slot = arena[index]; if (slot == null) // Lazily initialize slots createSlot(index); private volatile Slot[] arena = new Slot[CAPACITY]; 22 Implementing the Double-Checked Locking Pattern public class Exchanger<V> { • Synchronized statements can ... be used to implement patterns private void createSlot(int index){ like Double-Checked Locking final Slot newSlot = new Slot(); • Synchronization is done final Slot[] a = arena; “lazily” when initialization synchronized (a) { if (a[index] == null) is first performed a[index] = newSlot; } } Only synchronize during initialize private Object doExchange(...) { ... final Slot slot = arena[index]; if (slot == null) // Lazily initialize slots createSlot(index); private volatile Slot[] arena = new Slot[CAPACITY]; 23 End of Java Monitor Objects: Synchronization (Part 2) 24