Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

The below Javadoc is an snippet of HashMap documentation. Why authors would emphasize on putting a lock on the object that encapsulate a HashMap? Lock on the actual HashMap Object makes for sense.

Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map. If no such object exists, the map should be "wrapped" using the Collections.synchronizedMap method...

share|improve this question

2 Answers 2

Encapsulation is necessary here in order to restrict direct access of client code to methods of HashMap.

As for recommendation on what object to use as a lock, it serves a purpose to allow client code to iterate over the map in a thread safe way.

If you intend your map to be synchronized but lock on actual HashMap object, without hiding (encapsulating) it, then any code having access to that object would be able to invoke its unsynchronized methods and break synchronization. Purpose of encapsulation in this case is stated further in javadocs you refer: "to prevent accidental unsynchronized access to the map".

Documentation also refers to Collections.synchronizedMap as an example on how one is expected to synchronize:

Returns a synchronized (thread-safe) map backed by the specified map. In order to guarantee serial access, it is critical that all access to the backing map is accomplished through the returned map...

You see, synchronizedMap documentation reiterates the importance ("it is critical") for the client code not accessing "backing map" directly.

This documentation also further provides the example explaining why it is recommended to synchronize on the enclosing object:

It is imperative that the user manually synchronize on the returned map when iterating over any of its collection views:

  Map m = Collections.synchronizedMap(new HashMap());
      ...
  Set s = m.keySet();  // Needn't be in synchronized block
      ...
  synchronized (m) {  // Synchronizing on m, not s!
      Iterator i = s.iterator(); // Must be in synchronized block
      while (i.hasNext())
          foo(i.next());
  }

Failure to follow this advice may result in non-deterministic behavior.

You see, in the above code example, if client code would not have access to "known by convention" lock object, it would be impossible to properly synchronize: some other code could have used other lock to wrap the iteration which would lead to unsynchronized access.

share|improve this answer
1  
I don't think this was the question. Given an object that encapsulates the HashMap, the quoted JavaDoc states that for synchronizing access to a hash map, one should preferably lock on that containing object, not on the HashMap object. IOW synchronized(this) versus synchronized(this.private_map). If anything, that scheme seems more vulnerable to client code doing unsynchonized access to the map! –  delnan May 26 at 6:14
    
The part you quote is preceded by "[...] the map should be "wrapped" using the Collections.synchronizedMap method. This is best done at creation time". The wrapping into a synchonizedMap should be done in this way to prevent accidental unsynchronized access. The wrapper does encapsulate the wrapped map, but as explained before that does not explain the section OP quoted. –  delnan May 26 at 6:18
1  
But the doc does not recommend using synchronizedMap as go-to solution. It recommends manually synchronizing on the encapsulating object, with synchronizedMap as fallback when there is no such encapsulating object. Notably, it also advises against locking on the HashMap even when there is a encapsulating object. The last thing seems to be the core of OP's inquiry. Encapsulating to prevent unsync'd access is important, but not the point: Why should one not lock on the HashMap, provided it (or even regardless of whether) is properly encapsulated? –  delnan May 26 at 6:20
    
That wasn't what I said. Suppose we write a class that needs to be thread safe and uses a HashMap. For reasons you describe, we encapsulate the HashMap completely. We furthermore need to synchronize access to the map now that we're sure we're the only ones with access to it. As you also note correctly, we don't need to create another wrapper object, we've already encapsulated the map. We only need to decide whether to go synchronized(this) or synchronized(this.map). My intuition and OP's says it doesn't matter and the latter looks fine. The JavaDoc says the former should be used. Why? –  delnan May 26 at 6:29
    
@delnan upon further checking, your concerns make sense. I rewrote the answer –  gnat May 26 at 6:55

I understand it as saying that an "easy" way is to use the synchronized wrappers or make the class holding the map synchronized (I.e. using synchronized methods, which is what the wrappers does essentially).

But there are other ways, such as synchronising on the map itself if it is private and final, using a separate lock object or using a ConcurrentMap. I wouldn't overthink what is said here and simply apply usual concurrency patterns.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.