Java Concurrency In Practice - Question to Ask
Thread Safety
What are the differences between Concurrency and Parallel?
What is reentrancy lock?
Simple race condition:
- read-modify-write
- check-then-act
Guarded by a lock
- For every invariant that involves more than on variable, all the variables involved in that invariant must be guarded by the same lock
- Avoid holding locks during lengthy computations or operations at risk of not completing quickly such as network or console I/O
Sharing Objects
Locking & Visibility
- Related to
Phantom read
in DB. - Reordering (JVM allow reordering)
1 | public class NoVisibility { |
Lesson: Always use the proper synchronization whenever data is shared across threads.
Nonatomic 64-bit operations (
Long
andDouble
)Locking is not just about mutual exclusion; it is also about memory visibility
volatile
variables (use with caution)
1 | volatile boolean asleep; // will be set by other thread |
- Locking can guarantee both visibility and atomicity; volatile variables can only guarantee visibility;
Publication and escape
alien
method- Inner class instances contain a hidden reference to the enclosing instance
1
2
3
4
5
6
7
8
9
10public class ThisEscape {
public ThisEscape(EventSource source) {
source.registerListener(
new EventListener() {
public void onEvent(Event e) {
doSomething(e);
}
}
});
} - Do not allow the
this
reference to escape during construction (A common mistake: start a thread from a constructor)
Thread confinement
- Design consideration
Confine the modification to a single thread to prevent race conditions forvolatile
variables - Stack confinement V.S.
ThreadLocal
Immutability
Unmodifiable state, all fields are final
, and proper construction.
- Immutable objects are always thread-safe.
- It is a good practice to make all fields
final
unless they need to be mutable.1
2
3
4
5
6
7
8
9
10
11
12
13@ThreadSafe
public class VolatileCachedFactorizer implements Servlet {
private volatile OneValueCache cache = new OneValueCache(null, null):
public void service(ServletRequest reg, ServletResponse resp) {
BigInteger i = extractFromRequest(req);
BigInteger[] factors = cache.getFactors(i);
if (factors == null) {
factors = factor(i);
cache = new OneValueCache(i, factors);
}
encodeIntoResponse(resp, factors);
}
}
Safe publication idioms
Provided the object is effectively immutable
- Initializing an object reference from a static initializer;
- Storing a reference to it into a
volatile
field orAtomicReference
; - Storing a reference to it into a
final
field of a properly constructed object; or Storing a reference to it into a field that is properly guarded by a lock (Java native implementation likeConcurrentLinkedQueue
, static initializers);
Safely published effectively (why, research happen-before
relationship in JVM memory model) immutable objects can be used safely by any thread without additional synchronization.
Lesson:
- Immutable objects can be published through any mechanism
- Effectively immutable objects must be safely published;
- Mutable objects must be safely published, and must be either thread-safe or guarded by a lock for inner state.
Composing Objects
Consider the whether:
- The reference assignment is thread-safe or not
- The object is thread-safe or not
Pattern:
- Identify the variables that form the object’s state;
- Identify the invariants that constrain the state variables; (State ownership, who control the lock)
- Establish a policy for managing concurrent access to the object’s state.
Instance confinement
The Java monitor pattern
- Intrinsic lock is public accessible. Clients may use it correctly or incorrectly.
Delegating thread safety
- Independent state variables
Composition
- Favor composition over inheritance (and access to public intrinsic lock).
Building Blocks
Synchronized collections
Problems:
- Compound actions -> Know which lock to lock (check-then-act)
- Iterators and
ConcurrentModificationException
- Hidden iterators (e.g. Iteration hidden within string concatenation)
Concurrent collections
Replacing synchronized collections with concurrent colections
ConcurrentHashMap
: weakly consistentCopyOnWriteArrayList
: as long as an effectively immutable object is properly published, no further synchronization is requiredBlocking queues and the producer-consumer pattern
SynchronousQueue
: direct handling from producer to consumerSerial thread confinement -> Pass ownership/&make visibiable to other thread
Deque and work stealing
Blocking and interruptible methods
- Interruption is a cooperative mechanism
Synchronizers
Latches: A latch acts as a gate. Lates can be used to ensure that certain activities do not proceed until other one-time activities complete. Used to wait other event
FutureTask: Also acts like a latch
Semaphores: Counting semaphores are used to control the number of activities that can access a certain resource or perform a given action at the same time. e.g. Bounded resource (list, set, map)
Barriers: All the threads must come together at a barrier point at the same time in order to proceed. Used to wait other threads. e.g.
CyclicBarrier
Reinvent Wheels: Case: Cache
Task Execution
Using an Executor
is usually the easiest path to implementing a producer-consumer design in your application.
Thread pools
Executor
lifecycle
Running
Shutting Down
Terminated
Boundary of task
Lifecycle of a task by Executor
:
- created
- submitted
- started
- completed
e.g. Future
Assigning a different type of task to each worker does not scale well
ExecutorCompletionService
Executor
meets BlockingQueue
invokeAll
Java Concurrency In Practice - Question to Ask
http://puxiao.me/uncategorized/Java-Concurrency-In-Practice-Question-to-Ask/