Java Concurrency in Practice

advertisement
Java Concurrency in Practice
(ISBN: 0-321-34960-1)
Chapter 2 – Thread Safety




Writing thread-safe code is managing access to shared, mutable state
Thread-safe class != thread-safe program
Thread-safe class:
o Encapsulates it’s own state
o Behaves correctly when accessed from multiply threads
with no additional synchronization on the part of the caller
Synchronization mechanisms in Java
o synchronized
o volatile
o locks
o atomic variables
 Sharing objects safely (see also “Safe Publication” below):
o Thread-confined – no sharing
o Thread-safe:
 Immutability (properly constructed)
 Effective immutability (state isn’t modified)
 Locks, atomic variables/operations, volatile, static init
o Explicitly guarded by a lock





Data race = synchronization is not used to coordinate access to shared state
Race condition = correctness of computation depends on the timing
o Check-Then-Act or Read-Modify-Write
 Observation may become invalid when action is taken
o Update state in a single atomic operation to preserve state consistency
o Compound actions on shared state must be made atomic
o Every shared, mutable variable should be guarded by exactly one lock
o All variables involved in invariant must be guarded by the same lock
o Additional locking is required when multiply operations are combined into
compound action
o Synchronize the shortest possible code path
 Similar to DB transactions – “keep them short and sweet!”
 .. but don’t go too far – acquiring and releasing locks has overhead
Race condition != Data race
Mutex – mutual exclusion lock, at most one thread may own the lock
Liveness – activity gets into state permanently unable to make forward progress:
o Deadlock – each thread has a resource needed by another
o Livelock – thread keeps retrying an operation that always fails
o Starvation – denied access to resources required to make progress
Chapter 3 – Sharing Objects

Visibility:
o There’s no guarantee that operations in one thread will be performed in the
order given by the program, as long as the reordering is not detectable
from within that thread, even if the reordering is apparent to other
threads.
o Reading / writing mutable state without synchronization:
 Stale values (READ_UNCOMMITED)
 Losing updates
 Observing object in an inconsistent state
o Happens Before – ordered before and visible:
 Everything thread A did in or prior to synchronized block HB
B executes a synchronized block guarded by the same lock
 Thread A writes to volatile variable HB thread B reads it
 All variables visible to A before become visible to B as well
o volatile:
 Shared variable, no re-ordering with other memory operations
 Never cached in registers or CPU caches
 Read always returns the most recent write by any thread
 Used for:
 Ensuring visibility of their own state
 Ensuring visibility of the object they refer to
 Indicating an important lifecycle (init/shutdown) event
o Completion, interruption, status flag
 Used when:
 Writes do not depend on current value
o Unless a single thread only updates the variable
 Doesn’t participate in invariants with other state variables
 Locking is not required for any other reason while accessed
 Locking = visibility + atomicity
 Volatile = visibility only!
 Writes and reads of volatile fields have similar memory
consistency effects as entering and exiting monitors, but do
not entail mutual exclusion locking.
 Volatile ref to immutable holder (with multiply state variables):
 When holder variables are updated – new one is created
 When volatile is set – new data becomes immediately visible

Publication and escape:
o Alien method – behavior is not fully specified by the class
 Methods in other classes
 Overridable methods – neither private nor final
o Escaped – object published when it should not
o Publishing:
 Store a reference in a public static field
 Returning a reference from a non-private methods
 Passing an object to an alien method
 Publish an inner class instance
 Contains hidden reference to enclosing instance
o Safe construction:
 Do not allow this to escape during constraction!
 Starting a thread
 Registering event listener
 Additional methods – start(), newInstance(), etc

Thread confinement:
o Data is only accessed from a single thread
 Ex: Swing event dispatch thread
 Ex: Connection object in the JDBC connection pool
 Local variables
 ThreadLocal
o Ad-hoc confinement:
 Responsibility falls entirely on the implementation
 Single-threaded system – simplicity over fragility
 Deadlock avoidance
 volatile update
o Stack confinement:
 Object can only be reachable through local variables
 Primitively typed local variables – there’s no reference!
 Object confined to the executing thread only
o ThreadLocal confinement:
 Values are stored in the Thread object itself:
public T get()
{
ThreadLocalMap m = Thread.currentThread().threadLocals;
Entry
e = m.getEntry( ThreadLocal this );
return (( T ) e.value );
}

Immutability:
o Immutable object:
 All fields are final
 Non-final fields – lazily + deterministically from immutable state
 Benign data-race
 String.hashCode()
 State can not be modified after construction (always thread-safe!)
 Properly constructed – this didn’t escape during construction
o Immutable objects may be replaced

Safe Publication
o You cannot rely on integrity of partially constructed objects
o Safe: Object and object’s state made visible to other threads
o Improperly published objects:
 holder = new Holder(42);
 Other threads could see a stale value for the holder reference
 Other threads could see a stale values for the state of the Holder
 Object constructor first writes default values to all fields
 “/usr/tmp”.substring( 4 ): “/usr” => “/tmp”
 A thread may see a stale value the first time, an up-to-date later
o Object reference is visible != state of the object is visible as well
o Immutable objects may be published and used without synchronization
 Unmodifiable state + all fields final + proper construction
o Safe publication:
 Static initializer
 volatile field
 AtomicReference
 final field of a properly constructed object
 Field that is properly guarded by a lock
 Hashtable, synchronizedMap, ConcurrentMap
 Vector, CopyOnWriteArrayList, CopyOnWriteArraySet
 synchronizedList, synchronizedSet
 BlockingQueue, ConcurrentLinkedQueue
 Future, Exchanger
o Publication requirements:
 Immutable objects – any mechanism
 Effectively immutable – safely
 Mutable – safely + must be either thread-safe or guarded by a lock
o Object sharing policies:
 Thread-confined – owned /modified exclusively by one thread
 Shared read-only – concurrent reads, no modifications
 Immutable + effectively immutable
 Shared thread-safe – free access without further synchronization
 Guarded
– can be accessed only with a specific lock held
Chapter 4 – Composing Objects

Thread-safe class design:
o Identify variables forming object’s state and identify state space
 Smaller state space – easier to reason about it
 final fields
– less possible states
 Immutable objects – a single state only !
 State ownership
– state owner decides on the locking protocol
 Ownership implies control
 Publishing a reference = shared ownership
o Identify the invariants / postconditions constraining state’s variables
 Valid / invalid states / state transitions
 State dependent operations – fail or wait (block)
 Next state = f (current) => compound action
 Invalid states
=> state variables encapsulation
 Invalid state transitions => operation must be atomic
 Multivariable invariants => atomicity requirements
o Establish a policy for concurrent access to state + holding invariants
 Immutability, atomicity, thread confinement, locking

Instance confinement (of not thread-safe object):
o Object is encapsulated with another object + appropriate locking
o Encapsulating an object => preserve it’s invariants,
encapsulating it’s synchronization => enforce it’s sync policy
o Encapsulating data with an object confines an access to it
 Class instance – private fields
 Lexical scope – local variable
 Thread
– object passed as an argument
o Objects don’t escape on their own, they must be published beyond the scope
o Collections.synchronizedXXX()
o Monitor pattern: private final Object lock = new Object();
 “Transactions” are shorter than using an intrinsic lock
 Encapsulates the lock – clients cannot acquire/misuse it

Delegating thread safety to thread-safe components
o Independent variables + no invalid state transitions => delegate
o State variable can be published:
 Thread-safe
 Doesn’t participate in any invariants
 Has no prohibited state transactions

Adding functionality to existing thread-safe classes
o Modify/extend the original class
o Helper + client-side locking – use X with same lock X uses to guard it’s state
o Composition + monitor pattern
Chapter 5 – Building Blocks

Synchronized Collections
o All accesses to the collection’s state are serialized
o Hashtable, Vector, Collections.synchronizedXxx()
o Compound actions – client-side locking (lock=collection itself) to guard
o Compound actions:
 Iteration
 Navigation
 Conditional operations, like put-if-absent
 Thread-safe, but behavior may be surprising
o ConcurrentModificationException
 Fail-fast iterators
 Best-effort – modification count check is not synchronized
 Iterate the copy instead
 Collection must still be locked while clone/copy is made
 Collection hidden iterators
 toString
 hashCode
 equals
 containsAll
 removeAll
 retainAll
 Constructors taking other collections as an argument

Concurrent Collections
o Concurrent access from multiply threads (using fine-grained locks)
 Dramatic scalability improvements over synchronized collections
 Map
 ConcurrentHashMap
 ConcurrentSkipListMap
 List
 CopyOnWriteArrayList
 Set
 CopyOnWriteArraySet
 ConcurrentSkipListSet
 Queue
 ConcurrentLinkedQueue
o Iterators are weakly consistent instead of fail-fast
 Tolerates concurrent modifications
 May reflect modifications made to collections
o size, isEmpty are only estimations
o Never locked for exclusive access – no client-side locking is available
o ConcurrentMap – atomic compound operations:
 putIfAbsent
 remove (remove-if-equal)
 replace (replace-if-equal)
o CopyOnWriteArrayXxx
 As long as an effectively immutable object is properly published
(volatile) – no further synchronization is required to access it
 New copy is published every time collection is modified
 Iterators keep reference to array current at the start of iteration
 Arr never changes – sync only to ensure visibility of elements
 Multiply threads can iterate without interference
 ConcurrentModificationException never thrown
 Elements returned exactly as they were when iterator created

Blocking Queues - Producer-Consumer
o One shared work queue for all consumers
o Bounded/unbounded queues
 ArrayBlockingQueue
– bounded, backend by an array
 DelayQueue
– unbounded, taken after delay expired
 LinkedBlockingDeque
– optionally bounded, linked nodes
 LinkedBlockingQueue
– optionally bounded, linked nodes
 PriorityBlockingQueue – unbounded PriorityQueue
 SynchronousQueue
– insert => consumer or blocks
o Serial thread confinement
 Handing off ownership of objects from producers to consumers
 Ownership transferred by publishing it safely
 New owner has exclusive access
 Example: object pools
o Deques – Work Stealing
 Every consumer has its own deque
 Empty deque – consumer steals work from the tail of other deque
 Consumers don’t contend for a shared work queue
 Stealing work from the tail – contention is reduced as well

Blocking and Interruptible methods
o Blocking/pausing a threads – waiting for:
 I/O completion, acquire a lock, wake up from sleep
 Result of computation in another thread
o Blocked thread waits for an event beyond its control before proceeding
o InterruptedException – blocking method
 When interrupted – will make an effort to stop blocking early
 Interrupt – a request to stop doing X when getting to a stop-point
 Propagate/rethrow the exception
 Restore interrupt – Thread.currentThread().interrupt()
 Do nothing = lose/swallow the evidence the thread was interrupted!

Synchronizers
o Properties:
 Encapsulate state determining whether threads arriving pass or wait
 Provide methods to manipulate that state
 Provide methods to wait efficiently for the synchronizer to enter state
o CountDownLatch – blocks until the current count reaches zero or timeout
 Waiting for events
o FutureTask
– cancellable asynchronous computation
 Computational process that may or may not have completed
o Semaphore
– controls number of activities that can access resource
 Permit acquired in one thread can be released from another
 Resource pools, blocking bounded collection
o CyclicBarrier – set of threads all wait for each other to reach a barrier
 Waiting for other threads
 Break down a problem into N independent sub-problems
o Exchanger
– bidirectional form of a SynchronousQueue
 Parties perform asymmetric activities
Download