Java Thread-safe State Design Pattern
Thread-safe State
Apart from the things mentioned here, this pattern also conveys the intent and benefits of the GoF State pattern, being an extension thereof. The term "behaviour" is interpreted more strictly so that an object is always considered to change its behaviour when its state changes.
Intent
Make sure that an object is observable only in a valid consistent state and that transitions between valid consistent states are atomic and side-effects occur if and only if the associated transition occurs validly.
Motivation
Consider a class where behaviour depends on more than one field and/or side-effects occur as a result of certain state-changes. Such behaviour can be very difficult to analyze for thread-safety and the safe classic approach is to synchronize all methods. Such behaviour can also be difficult to analyze for logical correctness, bringing the motivation for the state pattern into play.
The key idea is to leverage the state pattern and store the current state in an AtomicReference. Current state should be represented by an immutable object. State transitions are performed by a compareAndSet (CAS) operation and a retry on failure. For transitions with side-effects, the CAS is performed to a boilerplate blocking state, the side effects performed, the resultant state set and the blocking state released, whereby each thread released from the blocking state retries the attempted operation on the resulting state. The CAS always compares with the "this" reference of the state instance being transitioned from and can only succeed for one thread, all other threads attempting a simultaneous transition have to retry on the new state.
Applicability
Any object that has a method that has a more complex interaction with the object state than one of either a simple get or a simple set (in which case just marking the field volatile is simpler and more performant).
Structure (given as implementation examples)
Delegate all calls to an immutable state instance:
class Implementation implements Interface { private final AtomicReferencestate; public ... doSomething(...) { return state.get().doSomething(...); } private class StateA implements Interface { private final ... valueX; private final ... valueY; public ... doSomething(...) { .... valueX ... valueY ... } } }
Simple state changes performed by CAS or retry:
class Implementation implements Interface { private final AtomicReferencestate; public void setX(y) { state.get().setX(y); } private class StateA implements Interface { private final ... x; public void setX(y) { if (!state.compareAndSet(this, new StateA(y))) { state.get().setX(y); } } } }
State changes with side-effects CAS to a blocking state first:
class Implementation implements Interface { private final AtomicReferencestate; public void printAndSetX(y) { state.get().printAndSetX(y); } private class StateA implements Interface { private final ... x; public void printAndSetX(y) { BlockingState guard = new BlockingState(); if (state.compareAndSet(this, guard)) { try { print(x); state.set(new StateA(y)); } finally { guard.release(); } } else {
state.get().printAndSetX(y);
} } } private class BlockingState implements Interface { private final CountDownLatch latch = new CountDownLatch(1); public void printAndSetX(y) { try { latch.await(); } catch (InterruptedException e) { // Don't care. } state.get().printAndSetX(y); } private void release() { latch.countDown(); } } }
Participants
- Interface - defines the public interface.
- Implementation - maintains an AtomicReference to current StateImplementation, implements the public interface.
- StateImplementation - the implementation of the public interface for a particular state.
- BlockingState - specialized boilerplate StateImplementation that blocks all calls until released and then delegates to the current state.
Collaborations
- Implementation delegates relevant (usually all) calls to the current StateImplementation.
- StateImplementation performs state transitions by a state.compareAndSet(this, nextState) or retry the transition on the current state (which is different from "this" since CAS failed) so that each state object can only be transitioned from once.
- BlockingState blocks all calls until released, thereupon retries on new current StateImplementation.
Consequences
- Interactions with the object always occur with a consistent state of the object, the immutability of the state delegate guaranteeing a consistent result of the interaction and each separate interaction is therefore in effect atomic.
- State transitions are explicit and atomic.
- Performance seems to be as good as or better than a straightforward non-thread-safe implementatin with mutable fields. Performance is better than that of synchronization (compare "optimistic locking" versus "read/write locking") for applicable objects if some interactions do not entail state changes, especially when the object is reachable from more than one thread (even if access is never contended).
Comments
---------------------------------------------
Dissertation Writing | Dissertation Advice
Nursing assistant classes
Bahrain website design company
HOTEL SUITES IN WASHINGTON DC
dissertation service writing
essay title
dissertation-topics-examples.info
I really appreciate this wonderful post that you have provided for us. I assure this would be beneficial for most of the people.