5

I have a strange issue with HashMap.
There are multiple threads that accessing same hashmap (not threadsafe).

Sometime, the process gets stuck.

when I inspect the thread stack, i see many threads in state:

java.lang.Thread.State: RUNNABLE
    at java.util.HashMap.get(HashMap.java:303) 

Note this happens very rare. And can't be reproduced on demand.

Why it gets stuck?

There is no synchronization on hashmap.

keys are strings

user2479100
  • 105
  • 1
  • 2
  • 7

1 Answers1

22

There are multiple threads that accessing same hashmap (not threadsafe).

Sounds like you are using this HashMap in a threaded environment without proper synchronization. You are hitting a problem where the HashMap memory is corrupted and a thread is most likely spinning because of this. You cannot update an unsynchronized map and read from it using multiple threads. In some situations you can build a read-only map and then share it without synchronization in multiple threads.

I would suggest switching to use ConcurrentHashMap instead or wrap your HashMap with Collections.synchronizedMap(...).

To elaborate more, the issue here is two fold. You cannot have two threads updating an unsynchronized map because of race conditions when altering internal map data. Locking is necessary to ensure mutex and proper data synchronization. One thread might make changes not seen by the other thread which could overwrite them.

The other issue is memory synchronization. If one thread updates the HashMap in its memory, other threads won't necessarily get the same view of the map's storage. This isn't a problem until a thread gets partial memory update -- where some of the HashMap memory has been updated and other portions have not. You might, for example, get a portion of the bucket array or a portion of the bucket storage which when traversed causes the thread to spin.

One of the main reasons multi-processor boxes run threaded code faster is that the threads can use per-processor cached memory. The cached memory is the problem. One processor could be reading or changing its cached memory at the same time another processor is doing the same. Synchronizing local cached memory with central storage is one of things you need to worry about and the reasons why synchronization is so important.

If you are using a pre-populated HashMap that is only going to be read by your threads and never updated then it may be ok. I depends highly on how each of the threads got the reference to the new HashMap. If the HashMap was constructed and then populated and passed into the threads via their constructor (or before they were started) then you are good. However if the threads are already running then it depends on how they get a reference to the map. They may still get a partial copy of the map's memory depending on the circumstances and your memory architecture.

Gray
  • 115,027
  • 24
  • 293
  • 354
  • Can you elaborate on "HashMap memory is corrupted"? Any example of this and how can this happen ? – Lokesh Jun 12 '13 at 16:06
  • "You cannot update an unsynchronized map and read from it using multiple threads.". Why not? – Lokesh Jun 12 '13 at 16:09
  • 1
    @user2479100 it does not matter; however, this is strange. As I requested in a comment to your question, can you tell what your keys are? – fge Jun 12 '13 at 16:15
  • what is strange? I answered in post, keys are strings. why? – user2479100 Jun 12 '13 at 16:19
  • 4
    To answer "Why not?" specifically see here http://mailinator.blogspot.com/2009/06/beautiful-race-condition.html – John Vint Jun 12 '13 at 16:20
  • Your explanations makes sense but why would traversing a partially updated bucket cause a thread to spin? Thread should simply read the partially updated garbage value and move on, isn't it ? – Lokesh Jun 12 '13 at 16:22
  • 3
    Basically an entries next value points to an entry which references the original entry. This happens after a restructure, resulting in an infinite loop. I am assuming you saw very high CPU once it got stuck? – John Vint Jun 12 '13 at 16:22
  • I've updated my answer to talk about read-only HashMaps @user2479100. – Gray Jun 12 '13 at 16:30
  • Is it possible to reproduce this issue via a simple code? (simple main with threads and hashmap?) I want to be sure that the process stuck because of hashmap misuse, or maybe there is something else. – user2479100 Jun 13 '13 at 05:19
  • 1
    I'd do a thread dump of the process. If one of the threads is stuck in a `HashMap` method then you are guaranteed that it's the issue. – Gray Jun 13 '13 at 12:16