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
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