I want to provide locking access to a resource using Guava Striped Lock. E.g.
Striped<Lock> keyLocks = Striped.lazyWeakLock(10)
Lock lock = keyLocks.get("resourceId")
// use lock...
I cannot find any guide how to choose the correct number of stripes for:
Striped.lazyWeakLock(int stripes)
Should stripes
be bound to the number of processor cores or what?
There's no a general rule of thumb, it depends on a trade-off between concurrency level and memory consumption. The Striped
JavaDoc partially explains it:
A striped
Lock/Semaphore/ReadWriteLock
. This offers the underlying lock striping similar to that ofConcurrentHashMap
in a reusable form, and extends it for semaphores and read-write locks. Conceptually, lock striping is the technique of dividing a lock into many stripes, increasing the granularity of a single lock and allowing independent operations to lock different stripes and proceed concurrently, instead of creating contention for a single lock.The guarantee provided by this class is that equal keys lead to the same lock (or semaphore), i.e. if
key1.equals(key2)
thenstriped.get(key1) == striped.get(key2)
(assumingObject.hashCode()
is correctly implemented for the keys). Note that ifkey1
is not equal tokey2
, it is not guaranteed thatstriped.get(key1) != striped.get(key2)
; the elements might nevertheless be mapped to the same lock. The lower the number of stripes, the higher the probability of this happening....
Prior to this class, one might be tempted to use
Map<K, Lock>
, whereK
represents the task. This maximizes concurrency by having each unique key mapped to a unique lock, but also maximizes memory footprint. On the other extreme, one could use a single lock for all tasks, which minimizes memory footprint but also minimizes concurrency. Instead of choosing either of these extremes,Striped
allows the user to trade between required concurrency and memory footprint. For example, if a set of tasks are CPU-bound, one could easily create a very compactStriped<Lock> of availableProcessors() * 4
stripes, instead of possibly thousands of locks which could be created in aMap<K, Lock>
structure.
In other words, Striped
provides a flexibility to select a number of locks, which are distributed between the keys, based on their hash code. This allows to dynamically apply a trade-off between concurrency and memory footprint, while retaining the key invariant that if key1.equals(key2)
, then striped.get(key1) == striped.get(key2)
.