views:

418

answers:

2

I have read Java Concurrency in Practice and this is a great reference, but I would like to see a concise single page summary of the use cases of the java.util.concurrent package.

For instance:

  • Why use a concurrent collection over a synchronized collection?
  • When should the atomic classes be preferred over explicit locking?
  • When should Locks be used over synchronization?
  • What are the alternatives to wait() and notify(), notifyAll()?
  • When should a CompletionService be used?

What are the pros/cons and pitfalls to be aware of?

+9  A: 
  • 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.

oxbow_lakes
One use case for Locks is when you want different implementations for different clients. Eg, a multi-threaded client can use a standard lock, a single-threaded a noop lock, and in load tests for race condition detection you might want to use a lock that aborts on concurrent access.
+1  A: 
What are the alternatives to wait() and notify(), notifyAll()

One very good alternative to wait(), notify() and notifyAll() is to NOT USE THEM AT ALL.

200KLOC codebase here that is heavily multithreaded. We're spreading the load on countless cores and have armies of producers/consumers scheme etc.

Instances of wait(), notify() or notifyAll() in our code?

Zero.

I re-put the emphasis on the fact that it is an heavily multi-threaded application: latches, poison pills, java.util.concurrent.* and whatnots everywhere. But wait(), notify() or notifyAll(): zero instances.

This is really low-level stuff that should only have its uses in concurrency utilities/frameworks.

From Joshua Bloch, in "Effective Java", at the very beginning of the "Threads" chapter:

"If there is a library that can save you from doing low-level multi-threaded programming, by all means use it."

Webinator