I've taken a quick look at the source code, and it appears to me to be
somewhere in between.
It is segmented, and the Segment class extends ReentrantLock. However,
the lock is obtained only for methods that modify the segment. The code
uses volatile variables to permit pure read operations to go through
without any locking.
Patricia
Carfield Yim wrote:
I've read some article which saying that CHM is still locked, it just
divid the hashmap into few small hashmap internally so that the chance
of lock-wait is lesser, is that wrong?
On Fri, Dec 3, 2010 at 10:19 PM, Gregg Wonderly <[email protected]> wrote:
On 12/2/2010 3:48 PM, Patricia Shanahan wrote:
Gregg Wonderly wrote:
...
A second issue is that if you are designing a "container" class that
others
might use in multiplicity such that it could end up in a container, and
perhaps as a key data structure, it can be better to create an internal
locking object to perform synchronization on so that if the user of your
class
starts using your class as a locking object, the internal locking does
not
impact unrelated code paths.
...
For container objects, I would give the opposite advice, and recommend
making
the container itself the lock object.
There are cases for both I believe. ConcurrentHashMap, for example has no
locks performed on the instance. All locking is internal using mechanisms
other than synchronized.
The primary issue with using an internal lock, for me, is that I've found
that I end up with less opportunity for circular wait if I am in complete
control of when a lock is asserted.
For things where atomic views need to maintained through multiple operations
on the same instance, then a single global view lock will be important. As
the user of the container instance, you are more able to understand that
need in your application, so locking is your responsibility.
Many people have complained about CHM not being "the lock" itself, but it
really comes down to the fact that since it does not use synchronized
actions internally, it can not make the object be "the lock".
With this in mind, I've started trying to internalize more locking so that
for things that I do need to "adjust internal performance" on, I don't have
to go everywhere else and change locking use to be in line with the change
from synchronized to Lock.
Locking with instances via synchronized was convenient, but I'd suggest that
not doing that provides a more plastic model that you can more readily
adjust.
I also find that I will put more application operations into the APIs to
help me control and optimize those usage patterns. This seems to help me
create more relevant/useful APIs and fewer "containers". I.e. more simple
algorithms end up in the class implementation instead of strewn about the
application.
Gregg Wonderly