Download Threadsafe design A threadsafe class Counter object used as

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
February 22, 2017
Composing Objects
Untitled Sheets
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
HOM/FHTenL
Untitled Sheets
February 22, 2017
Threadsafe design
1/30
Untitled Sheets
The design process for a threadsafe class should include
three basic elements:
Identify the variables (members) that form the object’s
state;
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
Identify the invariants that constrain the state variables;
Establish a policy for managing concurrent access to
the objects state.
HOM/FHTenL
Untitled Sheets
February 22, 2017
A threadsafe class
2/30
Untitled Sheets
HOM
@ThreadSafe
p u b l i c f i n a l c l a s s Counter {
@GuardedBy ( ” t h i s ” ) p r i v a t e l o n g v a l u e = 0 ;
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
publi c synchronized long getValue () {
return value ;
}
}
publi c synchronized long increment () {
i f ( v a l u e == Long . MAX VALUE)
throw new I l l e g a l S t a t e E x c e p t i o n ( ” c o u n t e r o v e r f l o w ” ) ;
r e t u r n ++v a l u e ;
}
HOM/FHTenL
Untitled Sheets
February 22, 2017
Counter object used as monitor
3/30
Untitled Sheets
HOM
Threadsafe design
t1:Tread
t2:Tread
:Counter
Confinement (revisited)
Java monitor pattern
Delegating thread safety
[lock acquired]increment()
[blocked]getValue()
[lock acquired]
value
HOM/FHTenL
Untitled Sheets
February 22, 2017
4/30
1
February 22, 2017
Composing Objects
Synchronisation requirements
Untitled Sheets
HOM
You cannot ensure threadsafety without understanding
an object’s invariants and postconditions. Constraints
on the valid values or state transtions for state variables
can create atomicity and encapsulation requirements.
E.g. the Counter class:
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
the state is determined by the value of value.
Counter has a constraint: value is not negative.
increment() has a postcondition: the only valid state
is that value is indeed incremented by 1.
HOM/FHTenL
Untitled Sheets
February 22, 2017
Confinement revisited
5/30
Untitled Sheets
HOM
Encapsulating data within an object confines access to
the data to the object’s methods, making it easier to
ensure the data is always accessed with the appropriate
lock held.
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
@ThreadSafe
public c l a s s PersonSet {
@GuardedBy ( ” t h i s ” )
p r i v a t e f i n a l Set<P e r s o n > mySet = new HashSet<P e r s o n > ( ) ;
p u b l i c synchronized void addPerson ( Person p ) {
mySet . add ( p ) ;
}
p u b l i c synchronized boolean containsPerson ( Person p ) {
r e t u r n mySet . c o n t a i n s ( p ) ;
}
}
i n t e r f a c e Person {
}
HOM/FHTenL
Untitled Sheets
February 22, 2017
PersonSet object used as monitor
6/30
Untitled Sheets
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
HOM/FHTenL
Untitled Sheets
February 22, 2017
Confinement makes threadsafeness easier
The state of class PersonSet is managed by a HashSet
which is not threadsafe, but mySet is private and not
allowed to escape: confinement.
7/30
Untitled Sheets
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
Access methods addPerson and containsPerson
acquire a lock on the PersonSet. Therefore
PersonSet is threadsafe.
Confinement makes it easier to build thread-safe classes
because a class that confines its state can be analyzed
for thread safety without having to examine the whole
program.
HOM/FHTenL
Untitled Sheets
February 22, 2017
8/30
2
February 22, 2017
Composing Objects
Monitor programming model
Untitled Sheets
HOM
The monitor as defined by Hoare is similar but not the
same as the Java model.
Hoare’s monitor makes, in Java terms, all methods in a
class synchronized. In the Java variant, locking is
reentrant (by the same Thread).
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
In the Java monitor pattern, all the object’s state is
encapsulated by the object and guarded by the object’s
own intrinsic lock.
This is the lock you use when you make a method
synchronized. As an example: see the Counter class.
HOM/FHTenL
Untitled Sheets
February 22, 2017
Using a auxiliary object as lock
Untitled Sheets
The instance myLock of type Object is used as a lock. This
is a typical Java idiom or ’Pattern’.
public class PrivateLock {
p r i v a t e f i n a l O b j e c t myLock = new O b j e c t ( ) ;
@GuardedBy ( ” myLock ” ) Widget w i d g e t ;
}
9/30
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
v o i d someMethod ( ) {
s y n c h r o n i z e d ( myLock ) {
// A c c e s s o r m o d i f y t h e s t a t e o f w i d g e t
}
}
There is a pattern here! The java Monitor-pattern.
HOM/FHTenL
Untitled Sheets
February 22, 2017
PrivateLock
10/30
Untitled Sheets
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
HOM/FHTenL
Untitled Sheets
February 22, 2017
Delegating thread safety
11/30
Untitled Sheets
Monitor-based vehicle tracker implementation: thread safety
although MutablePoint is not thread-safe.
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
@ThreadSafe
Delegating thread safety
public class M o n i t o r V e h i c l e T r a c k e r {
@GuardedBy ( " this " )
private final Map < String , MutablePoint > locations ;
public M o n i t o r V e h i c l e T r a c k e r ( Map < String ,
MutablePoint > locations ) {
this . locations = deepCopy ( locations );
}
public synchronized Map < String , MutablePoint > getLocations () {
return deepCopy ( locations );
}
public synchronized MutablePoint getLocation ( String id ) {
MutablePoint loc = locations . get ( id );
return loc == null ? null : new MutablePoint ( loc );
}
HOM/FHTenL
Untitled Sheets
February 22, 2017
12/30
3
February 22, 2017
Composing Objects
MonitorVehicleTracker sequence diagram
Untitled Sheets
HOM
Threadsafe design
:Client
Confinement (revisited)
Java monitor pattern
Delegating thread safety
new
new(locs)
locs:HashMap
locations:HashMap
mvt:MonitorVehicleTracker
getLocations()
deepCopy(locs)
map
deepCopy(locs)
getLocation(id)
get(id)
location
new(location)
loc:MutablePoint
loc
HOM/FHTenL
Untitled Sheets
February 22, 2017
Immutable Point class: Mwha!
13/30
Untitled Sheets
HOM
Threadsafe design
@NotT hreadSafe
public class MutablePoint {
public int x , y ;
Confinement (revisited)
Java monitor pattern
Delegating thread safety
public MutablePoint () {
x = 0;
y = 0;
}
public MutablePoint ( MutablePoint p ) {
this . x = p . x ;
this . y = p . y ;
}
}
HOM/FHTenL
Untitled Sheets
February 22, 2017
Immutable Point
Untitled Sheets
If the components of our class are already thread safe, do we
need an addiditional layer of thread safety?
@Immutable
public c l a s s Point {
public final int x , y ;
}
14/30
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
public Point ( i n t x , i n t y ) {
this . x = x ;
this . y = y ;
}
See next slide for the DelegatingVehicleTracker which
uses a thread-safe (immutable) Point class and a
thread-safe Map implementation to store the locations using
immutable points.
HOM/FHTenL
Untitled Sheets
February 22, 2017
Delegating thread safety
15/30
Untitled Sheets
Method getLocations() returns a ’live’ view of the vehicle
locations.
If thread A calls getLocations() and thread B later
modifies the location of some of the points, those changes
are reflected in the Map returned earlier to thread A.
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
@ThreadSafe
public class DelegatingVehicleTracker {
p r i v a t e f i n a l ConcurrentMap<S t r i n g , P o i n t > l o c a t i o n s ;
p r i v a t e f i n a l Map<S t r i n g , P o i n t > u n m o d i f i a b l e M a p ;
p u b l i c D e l e g a t i n g V e h i c l e T r a c k e r (Map<S t r i n g , P o i n t > p o i n t s ) {
l o c a t i o n s = new ConcurrentHashMap<S t r i n g , P o i n t >( p o i n t s ) ;
unmodifiableMap = C o l l e c t i o n s . unmodifiableMap ( l o c a t i o n s ) ;
}
p u b l i c Map<S t r i n g , P o i n t > g e t L o c a t i o n s ( ) {
return unmodifiableMap ;
}
HOM/FHTenL
Untitled Sheets
February 22, 2017
16/30
4
February 22, 2017
Composing Objects
DelegatingVehicleTracker sequence diagram
Untitled Sheets
HOM
Threadsafe design
:Client
Confinement (revisited)
Java monitor pattern
Delegating thread safety
new
new(points)
points:HashMap
:Collections
dvt:DelegatingVehicleTracker
new(points)
locations:ConcurrentHashMap
unmodifiableMap(locations)
unmodifiableMap
getLocations()
unmodifiaableMap:Map
unmodifiableMap
HOM/FHTenL
Untitled Sheets
February 22, 2017
Independent state variables
17/30
Untitled Sheets
Delegation to more state variables is possible if these are
independent. See the VisualComponent class with two
List’s: one for KeyListeners and one for MouseListeners.
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
p u b l i c c l a s s VisualComponent {
p r i v a t e f i n a l L i s t <K e y L i s t e n e r > k e y L i s t e n e r s
= new C o p y O n W r i t e A r r a y L i s t <K e y L i s t e n e r > ( ) ;
p r i v a t e f i n a l L i s t <M o u s e L i s t e n e r > m o u s e L i s t e n e r s
= new C o p y O n W r i t e A r r a y L i s t <M o u s e L i s t e n e r > ( ) ;
public void addKeyListener ( KeyListener
k e y L i s t e n e r s . add ( l i s t e n e r ) ;
listener ) {
}
public void addMouseListener ( MouseListener l i s t e n e r ) {
m o u s e L i s t e n e r s . add ( l i s t e n e r ) ;
}
Placing an object in a CopyOnWriteArrayList, safely
publishes it to any thread that receives it from the collection.
HOM/FHTenL
Untitled Sheets
February 22, 2017
When delegation fails
18/30
Untitled Sheets
HOM
Two atomic integers with an additional constraint:
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
p u b l i c c l a s s NumberRange {
// INVARIANT : l o w e r <= u p p e r
p r i v a t e f i n a l A t o m i c I n t e g e r l o w e r = new A t o m i c I n t e g e r ( 0 ) ;
p r i v a t e f i n a l A t o m i c I n t e g e r u p p e r = new A t o m i c I n t e g e r ( 0 ) ;
public void setLower ( i n t i ) {
// Warning −− u n s a f e c h e c k −th en −a c t
i f ( i > upper . get ( ) )
throw new I l l e g a l A r g u m e n t E x c e p t i o n (
” can ’ t s e t l o w e r t o ” + i + ” > u p p e r ” ) ;
lower . set ( i ) ;
}
public void setUpper ( i n t i ) {
// Warning −− u n s a f e c he c k −th en −a c t
HOM/FHTenL
Untitled Sheets
February 22, 2017
NumberRange class does not sufficiently protect
its invariants
19/30
Untitled Sheets
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
t1:Thread
t1:Thread
new NumberRange(0,10)
:NumberRange
upper:AtomicInteger
lower:AtomicInteger
setLower(5)
get()
setUpper(4)
get()
10
0
set(5)
set(4)
HOM/FHTenL
Untitled Sheets
February 22, 2017
20/30
5
February 22, 2017
Composing Objects
When delegation fails
Untitled Sheets
Delegation threadsafety to two thread-safe variables:
invariant is not preserved!
How could we make NumberRange thread-safe?
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
Use locking to maintain the invariants by guarding
upper and lower by a single lock
HOM/FHTenL
Untitled Sheets
February 22, 2017
When delegation fails
21/30
Untitled Sheets
Delegation threadsafety to two thread-safe variables:
invariant is not preserved!
How could we make NumberRange thread-safe?
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
Use locking to maintain the invariants by guarding
upper and lower by a single lock
avoid publishing lower and upper to avoid ruining it’s
invariants.
HOM/FHTenL
Untitled Sheets
February 22, 2017
When delegation fails
21/30
Untitled Sheets
Delegation threadsafety to two thread-safe variables:
invariant is not preserved!
How could we make NumberRange thread-safe?
HOM
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
Use locking to maintain the invariants by guarding
upper and lower by a single lock
avoid publishing lower and upper to avoid ruining it’s
invariants.
Definition
If a class is composed of multiple independent thread-safe
state variables and has no operations that have any invalid
state transitions, then it can delegate thread safety to the
underlying state variables.
HOM/FHTenL
Untitled Sheets
February 22, 2017
Publishing underlying state variables
21/30
Untitled Sheets
HOM
Under what conditions can you publish those state
variables?
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
HOM/FHTenL
Untitled Sheets
February 22, 2017
22/30
6
February 22, 2017
Composing Objects
Publishing underlying state variables
Untitled Sheets
HOM
Under what conditions can you publish those state
variables?
It depends! on what invariants your class imposes on
those variables.
HOM/FHTenL
Untitled Sheets
February 22, 2017
Publishing underlying state variables
Untitled Sheets
February 22, 2017
February 22, 2017
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
22/30
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
22/30
Untitled Sheets
HOM
Under what conditions can you publish those state
variables?
It depends! on what invariants your class imposes on
those variables.
Making the state variable value of the Counter class
public (=publishing!) clients could change it into an
invalid value.
Don’t publish if you don’t need to!
If there aren’t any constraints, you can publish without
compromising thread safety.
Untitled Sheets
22/30
HOM
Publishing underlying state variables
HOM/FHTenL
Delegating thread safety
Untitled Sheets
Under what conditions can you publish those state
variables?
It depends! on what invariants your class imposes on
those variables.
Making the state variable value of the Counter class
public (=publishing!) clients could change it into an
invalid value.
Don’t publish if you don’t need to!
Untitled Sheets
Java monitor pattern
HOM
Publishing underlying state variables
HOM/FHTenL
Confinement (revisited)
Untitled Sheets
Under what conditions can you publish those state
variables?
It depends! on what invariants your class imposes on
those variables.
Making the state variable value of the Counter class
public (=publishing!) clients could change it into an
invalid value.
HOM/FHTenL
Threadsafe design
February 22, 2017
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
22/30
7
February 22, 2017
Composing Objects
Publishing underlying state variables
Untitled Sheets
HOM
Under what conditions can you publish those state
variables?
It depends! on what invariants your class imposes on
those variables.
Making the state variable value of the Counter class
public (=publishing!) clients could change it into an
invalid value.
Don’t publish if you don’t need to!
If there aren’t any constraints, you can publish without
compromising thread safety.
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
Definition
If a state variable is thread-safe, does not participate in any
invariants that constrain its value, and has no prohibited
state transitions for any of its operations, then it can safely
be published.
HOM/FHTenL
Untitled Sheets
February 22, 2017
A SafePoint class
22/30
Untitled Sheets
HOM
@ThreadSafe
public class SafePoint {
@GuardedBy ( ” t h i s ” ) p r i v a t e i n t x , y ;
Threadsafe design
Confinement (revisited)
Java monitor pattern
private SafePoint ( int [ ] a) {
this (a [0] , a [1]);
}
Delegating thread safety
public SafePoint ( SafePoint p) {
t h i s (p . get ( ) ) ;
}
public SafePoint ( int x , int y) {
this . x = x ;
this . y = y ;
}
public synchronized i n t [ ] get () {
r e t u r n new i n t [ ] { x , y } ;
}
public synchronized void set ( int x , int y ) {
this . x = x ;
this . y = y ;
}
}
HOM/FHTenL
Untitled Sheets
February 22, 2017
The PublishingVehicleTracker class
23/30
Untitled Sheets
HOM
SafePoint returns both x and y values at once by
returning an array without undermining thread safety.
Note the use of a private constructor in SafePoint!
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
@ThreadSafe
public class PublishingVehicleTracker {
p r i v a t e f i n a l Map<S t r i n g , S a f e P o i n t > l o c a t i o n s ;
p r i v a t e f i n a l Map<S t r i n g , S a f e P o i n t > u n m o d i f i a b l e M a p ;
p u b l i c P u b l i s h i n g V e h i c l e T r a c k e r (Map<S t r i n g , S a f e P o i n t > l o c a t i o n s ) {
this . locations =
new ConcurrentHashMap<S t r i n g , S a f e P o i n t >( l o c a t i o n s ) ;
t h i s . unmodifiableMap =
C o l l e c t i o n s . unmodifiableMap ( t h i s . l o c a t i o n s ) ;
}
p u b l i c Map<S t r i n g , S a f e P o i n t > g e t L o c a t i o n s ( ) {
return unmodifiableMap ;
}
public SafePoint getLocation ( String id ) {
return l o c a t i o n s . get ( id ) ;
HOM/FHTenL
Untitled Sheets
February 22, 2017
The PublishingVehicleTracker class
24/30
Untitled Sheets
HOM
Delegation to the underlying Concurrenthashmap
secures thread safety in PublishingVehicleTracker.
getLocations() returns an unmodifiable copy of the
underlying map.
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
A caller of getLocations() could change the locations
of the veicles but cannot add or remove vehicles
themselves.
If there are additional constraints on the valid values of
vehicle locations PublishingVehicleTracker is not
thread safety anymore.
HOM/FHTenL
Untitled Sheets
February 22, 2017
25/30
8
February 22, 2017
Composing Objects
Adding functionality
Untitled Sheets
HOM
We have a thread-safe class!!
Threadsafe design
We want to add a new operation without underminig its
threadsafety.
Confinement (revisited)
Java monitor pattern
Delegating thread safety
Example: put-if-absent operation. Should be atomic.
You do not own the Vector code, so use subclassing.
@ThreadSafe
p u b l i c c l a s s B e t t e r V e c t o r <E> e x t e n d s V e c t o r <E> {
// When e x t e n d i n g a s e r i a l i z a b l e c l a s s ,
// you s h o u l d r e d e f i n e s e r i a l V e r s i o n U I D
s t a t i c f i n a l l o n g s e r i a l V e r s i o n U I D = −3963416950630760754 L ;
}
p u b l i c synchronized boolean p u t I f A b s e n t (E x ) {
boolean absent = ! c o n t a i n s ( x ) ;
i f ( absent )
add ( x ) ;
return absent ;
}
HOM/FHTenL
Untitled Sheets
February 22, 2017
Client-side locking
26/30
Untitled Sheets
HOM
What if you don’t know your collection type?
E.g. by using the Collections.synchronizedList
wrapper.
Then use a ”helper” class:
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
@NotThreadSa fe
c l a s s B a d L i s t H e l p e r <E> {
p u b l i c L i s t <E> l i s t =
C o l l e c t i o n s . s y n c h r o n i z e d L i s t ( new A r r a y L i s t <E > ( ) ) ;
p u b l i c synchronized boolean p u t I f A b s e n t (E x ) {
boolean absent = ! l i s t . c o n t a i n s ( x ) ;
i f ( absent )
l i s t . add ( x ) ;
return absent ;
}
}
HOM/FHTenL
Untitled Sheets
February 22, 2017
Client-side locking - 2
Untitled Sheets
HOM
Why doesn’t this work?
putIfAbsent is synchronized!
It uses the wrong lock! (illusion of synchronization)
Use the same lock that the list uses ..!
’Check-then-act’ also here:
The documentation on Vector and on synchronized
wrapper classes shows that they support client-side
locking.
HOM/FHTenL
Untitled Sheets
February 22, 2017
Client-side locking - 3
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
28/30
Untitled Sheets
HOM
OK now.
Threadsafe design
Confinement (revisited)
@ThreadSafe
c l a s s G o o d L i s t H e l p e r <E> {
p u b l i c f i n a l L i s t <E> l i s t =
C o l l e c t i o n s . s y n c h r o n i z e d L i s t ( new A r r a y L i s t <E > ( ) ) ;
}
27/30
Java monitor pattern
Delegating thread safety
p u b l i c boolean p u t I f A b s e n t (E x ) {
synchronized ( l i s t ) {
boolean absent = ! l i s t . c o n t a i n s ( x ) ;
i f ( absent )
l i s t . add ( x ) ;
return absent ;
}
}
HOM/FHTenL
Untitled Sheets
February 22, 2017
29/30
9
February 22, 2017
Composing Objects
Composition
Untitled Sheets
HOM
Delegation instead of subclassing: often a better
approach.
It is assumed that the client after having constructed
the ImprovedList will access the underlying list only
through the ImprovedList.
Uses the java monitor pattern.
Threadsafe design
Confinement (revisited)
Java monitor pattern
Delegating thread safety
@ThreadSafe
p u b l i c c l a s s I m p r o v e d L i s t <T> i m p l e m e n t s L i s t <T> {
p r i v a t e f i n a l L i s t <T> l i s t ;
p u b l i c I m p r o v e d L i s t ( L i s t <T> l i s t ) { t h i s . l i s t = l i s t ; }
p u b l i c s y n c h r o n i z e d b o o l e a n p u t I f A b s e n t (T x ) {
boolean c o n t a i n s = l i s t . c o n t a i n s ( x ) ;
i f ( contains )
l i s t . add ( x ) ;
return ! contains ;
}
HOM/FHTenL
Untitled Sheets
February 22, 2017
30/30
10
Related documents