- Why use a concurrent collection over a synchronized collection?
Because a synchronized
collection only protects data from corruption due to concurrent access. This does not mean that the synchronized
collections are optimized for concurrent access. Far from it, in fact - a ConcurrentMap.putIfAbsent
is a much better mechanism for a compareAndSet
than locking the entire Map
for reads.
- When should the atomic classes be preferred over explicit locking?
The AtomicInteger
and AtomicLong
classes should always be used (in my opinion) over locking by hand with a primitive because they are more concise. Consider:
synchronized (lock) {
int old = counter;
counter++;
return old;
}
When compared with:
int old = counter.getAndIncrement();
I have to say though, that the classes suffer from their lack of waitability. For example, you oftend want some synchronized boolean where you wait
on the boolean condition. These were available as WaitableBoolean
in the old Doug Lea concurrency library but they were jettisoned in j.u.c
, I'm not sure why.
- When should Locks be used over synchronization?
This is a more complicated question because usage of Locks
carries some overhead. In fact, it's often said that there's no pint in using a ReadWriteLock
in typical cases. One scenario where locks must be used is where the locking of a resource and its unlocking cannot be done in the same lexical scope. synchronized
is powerless to help in cases such as these.
- What are the alternatives to wait() and notify(), notifyAll()?
await
, signal
and signalAll
- When should a CompletionService be used?
A completion service is useful in the case where the consumption of a result of a computation does not need to be accessed at the point the computation was submitted but where it is important that the completion of the computation (or its result, or success) be known by your program. This might be, for example, to monitor the proportion of failed tasks (which threw exceptions), or it may be for resource cleanup.