Download Synchronization - Vanderbilt University

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
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