240 likes | 253 Views
6894 · workshop in software design lecture 6 · october 19, 1998 · concurrent design patterns. background to lea’s book. book [Doug Lea, 97] Concurrent Programming in Java: Design Principles & Patterns concurrency focus on problems with natural concurrency; maybe just one CPU
E N D
6894 · workshop in software designlecture 6 · october 19, 1998 · concurrent design patterns
background to lea’s book • book • [Doug Lea, 97] Concurrent Programming in Java: Design Principles & Patterns • concurrency • focus on problems with natural concurrency; maybe just one CPU • compare to parallel programming • inherently sequential programs, many CPUs • additional specialized techniques needed for • distributed systems, realtime systems, databases • design • focus on structural design issues • not details of algorithms or protocols • patterns • motivation similar to GOF • explain and classify common techniques, with emphasis on terminology • more concerned with basics of achieving safety and liveness • less concern for flexibility • subclassing often mentioned (but more a problem than a solution?)
safety & liveness • two aspects of interference • safety: nothing bad happens • usually first concern • liveness: something good happens • often critical too: flood gates fail? • conflicting • most of the things that improve safety damage liveness, and vv • so many of Lea’s liveness patterns are really just ways to adjust safety patterns • finite & infinite • safety problems can be observed after a finite time • at 10 o’clock the train crashed • liveness problems may require infinite time • process may be unblocked just after you check! • but in practice, most liveness problems are very finite • most users know when an application is stuck in a loop
safety • safety problems • arise because of lack of synchronization • manifestations • events happen out of order • garbage results are produced • values are read that were never written • races • different schedulings give different outcomes • never assume thread with less computation to do will finish first! • often cause safety violations • make testing and debugging hard • example • textarea.display (“goodbye”); • textarea.display (“hello”); • outcome: “helgoolodbye”
liveness • reasons why a thread may not be live • contention or ‘starvation’ • another thread has taken over CPU resources • dormancy • wait without notify, suspend without resume • a simple coding error • deadlock • two threads in vicious cycle trying to access a lock • premature termination • killed by stop, eg • thread groups help • liveness is a global property • can design a component to be safe in all contexts • but hard to one live in all contexts • two components always live in other contexts may fail when run together
liveness example • code sample • class Document ( Document other_part; • synchronized void print () { System.out.println (“first line”); … System.out.println (“last line”); } • synchronized void printAll () { other_part.print (); print (); } } • does this work? other_part DOCUMENT
deadlock! • thread 1 thread 2 • letter.printAll • letter now locked • enclosure.printAll • enclosure now locked • letter.other_part.print • waiting for enclosure • enclosure.other_part.print • waiting for letter
approaches to ensuring safety & liveness (1) • proof • develop a mathematical argument for why program works • check by social consent or use theorem prover • advantages • gives lots of insight, may help improve design • good for subtle algorithms (abstract, and amortized over many uses) • disadvantages • exhorbitant cost, proofs not reusable • model checking • extract a state machine from the code (by hand or semiautomatically) • specify safety and liveness properties in a temporal logic • run model checker to find bugs • advantages • more cost-effective than proof • properties can be reused • disadvantages • gives little insight, confidence can be misleading
approaches to ensuring safety & liveness (2) • testing • run program and check properties as it executes • new, more sophisticated dynamic analyzers may test ‘all’ paths (eg, Rivet) • advantages • no extraction of model needed • to some extent, can do without source code • disadvantages • lower coverage than model checking • won’t work on partial programs • correctness by construction • establish standard policies & structures that guarantee properties • constrain design within these bounds • advantages • reuse of design expertise • reliable, practical, maintainable • disadvantages • not so flexible
java mechanisms: thread control • elements • java.lang.Thread to initiate and control new activities • keywords synchronized and volatile, used to control code in objects in >1 thread • methods wait, notify and notifyAll, defined in java.lang.Object • thread control • to create a thread • Runnable x = …; Thread t = new Thread (x); t.start () • to terminate a thread • x.run returns, or t.stop () • to temporarily halt a thread • t.suspend (), t.resume () • to suspend thread for given time • t.sleep (milis) • to wait for a thread to complete • t.join () • to check if a thread has started but not terminated • t.isAlive ()
java mechanisms: locking • locking • synchronized void foo (…) • foo cannot be executed while another synchronized method of this is running • but not atomic! unsynchronized methods can run • synchronized (foo) {…} • block cannot be executed while another thread has the lock on object foo • volatile instance variables • a compiler optimization: • t = v; … (no assignments to v) … ; u = v; • assume v has same value at both assignments • not valid in multithreaded code • marking v as volatile disables this optimization
java mechanisms: notification • wait, notify, notifyAll • o.wait (), o.notify (), o.notifyAll • may only be invoked by thread with lock on o • o.wait • suspends current thread • puts thread in wait queue for o • releases sync lock for o • o.notify • some thread t in the wait queue for o is removed • t blocks until lock on o is released • t acquires lock and continues at wait point • o.notifyAll • like notify, but for all threads in queue • should generally use rather than notify
lea’s patterns • programming idioms • how to use basic mechanisms • at level of individual code statements • eg, when to mark a variable as volatile • design patterns • how to assemble components • at granularity level of GOF patterns • eg, structural containment, completion callback • architectural styles • general organization schemes and policies • at granularity level of Garlan/Shaw architectures • eg, concurrency control schemes • online supplement • http://gee.cs.oswego.edu/dl/cpj • collects patterns from book in GOF style • but generally lower level than GOF patterns
immutability • basic idea • easiest way to avoid undesirable state changes • use objects that never change state! • eg, use String in place of StringBuffer • to make an object immutable • override Object.hashCode and Object.equals • methods: constructors, but not mutators • might make class final • partially immutable objects • can drop synchronization for methods that read immutable components • semi-immutable variables • variables that change value once • boolean latches, fields that get set from null to a fixed value • can exploit special constructions • eg, value can’t change between test and action
fully synchronized objects • synchronize every method of class • then locally sequential behaviour • each object does only one thing at a time • liveness concerns motivate weaking sync • make accessors unsynchronized (be careful!) • exploit immutability of instance vars • split locks or classes • example • Shape object has x, y, width and height vars • access to each {x, y} and {width, height} must be synchronized, but OK to access {x, height} • class splitting • form two classes, Location and Dimension, with synchronized methods • containing class, Shape, has unsynchronized methods • lock splitting • introduce a lock for each set of instance vars • location method now has block synchronized on location_lock
CLIENT ? RESOURCE structural containment • basic idea • achieve sync structurally by avoiding shared variables • compared to fully synchronized classes • less prone to liveness failures and more efficient • but very limited • class structure • client methods are synchronized • resource methods are unsynchronized • managing ownership • fixed: never changes • exclusive resource: changes owner, but at most one • basic ops: acquire, forget, give, take, exchange • protocol: eg, ring
asynchronous invocation • basic idea • make message passing really message passing! • client need not wait for service to complete • example • in Observer pattern, notification can cause deadlock • subject is waiting to notify observer • observer is waiting to get state from subject • so make notification asynchronous • strategies • direct invocation • normal invocation, but in unsynchronized method • host object can ‘continue’ (in another thread) • thread-based • perform invocation within a new thread • command-based • create message or event object and pass to other object that executes it
optimistic methods • basic idea • method attempts action, assuming success • if action fails, rolls back and cancels • failure may be due to • bad interleaving of threads • network failure or machine down • … programming error • why? • in databases: less locking, better performance • in distributed system, failure impossible to predict • design issues • how to rollback state • how to identify failures • typical elements • transaction ids, timestamps • make backup copies • commit protocol
concurrency control • motivation • want to separate • synchronization & control • base mechanisms • reuse of ‘ground’ classes • safety and liveness properties • guaranteed by CC layer • patterns • Subclassing • overriding method adds sync (& maybe tracks extra state to do so) • Readers & Writers • partition methods into read & write • superclass tracks #reading/writing threads • read/write methods are hooks: abstract methods implemented in subclass • Adapters • control passes through synchronized method that delegates to unsynchronized method • Acceptors
read-only adapter • basic idea • adapter provides immutable view of mutable object • an example of concurrency control • layering sync mechanism over ‘ground’ object • alternative • view through immutable interface • (but allows client to cast to mutable class) • notes • client is not protected from changes, only from making changes! • so object does not appear to be immutable CLIENT IMMUT MUT CLIENT MUT IMMUT
acceptors • basic idea • concurrency control by exploiting reflection with meta-objects • pass around representations of messages • Acceptor is object that accepts generic message • public interface Acceptor { public void accept (MessageType msg); } • other names for accept: handle, action, perform, post, execute • examples of messages • instance of java.awt.Event • Listener is a kind of Acceptor • instance of Runnable class: execution by invoking run • instance of Class class: execution by creation of new object
services • common thread idioms • Command: service that never conveys result to client • Completion: finding out if a service is done • Group Services: allocate service to several threads, invisible to client • … not directly supported by Java
futures • motivation • client needs to know when service completes • want to avoid polling service • join • block until service thread completes, then use result • serviceThread.join(); • result = service.result (); • idea of futures • a programming language feature • call to service is asynchronous • immediately returns result • no blocking until result is used • can simulate in Java • service maintains reference to its thread • join is encapsulated in call to result method
completion callback • motivation • want something more flexible than join-based technique • eg, >1 action on completion • structure • Client passes itself to Service • when Service is done, it calls • client.done () • client.failed () • etc CLIENT SERVICE SERVICE-CLIENT