Vasilis
Vasilis

Reputation: 2832

Strange Deadlock(?)

I am having a very strange deadlock in a Java application that uses two threads. Both threads read and write data to a shared hashmap. To avoid synchronization problems I made synchronized the functions that read and write data the hashmap:

private synchronized boolean identifiedLinksHasKey(String linkKey){
        return Parser.identifiedLinks.containsKey(linkKey);
}


private synchronized void putToIdentifiedLinks(String key, TreeSet<String> aset){     
        Parser.identifiedLinks.put(key,aset);
}

However, the program hangs at some point (which doesn't happen when I run it with a single thread). To debug my application I used jstack after it hangs, which gave me the following thread dump:

"Thread-2" prio=6 tid=0x0000000006b09800 nid=0x78fc runnable [0x00000000083ef000 ]
java.lang.Thread.State: RUNNABLE at java.util.HashMap.put(Unknown Source) at bgp.parser.Entry.putToIdentifiedLinks(Entry.java:297) - locked <0x00000000853f2020> (a bgp.parser.Entry) at bgp.parser.Entry.parseTxtFile(Entry.java:141) at bgp.parser.Entry.run(Entry.java:31)

"Thread-1" prio=6 tid=0x0000000006b52800 nid=0x9390 runnable [0x00000000082ef000 ]
java.lang.Thread.State: RUNNABLE at java.util.HashMap.getEntry(Unknown Source) at java.util.HashMap.containsKey(Unknown Source) at bgp.parser.Entry.identifiedLinksHasKey(Entry.java:281) - locked <0x00000000853f00e0> (a bgp.parser.Entry) at bgp.parser.Entry.parseTxtFile(Entry.java:134) at bgp.parser.Entry.run(Entry.java:31)

It seams that the two threads access simultaneously the two synchronized functions which contradicts the meaning of synchronization. The same situation happens even if I use object locks. Although the threads' state is not BLOCKED but RUNNABLE they behave as blocked, probably because they access the same hashmap at the same time.

I would really appreciate if someone could explain me why this strange situation happens.

Upvotes: 1

Views: 1650

Answers (5)

TinkerTank
TinkerTank

Reputation: 5805

The 'synchronized' keyword locks at object-level. That is: No two synchronized methods can be running at the same time within one object.

Is it possible that there are two distinct objects that are being called from the two separate threads?

edit: re-visiting the stack trace, I'm getting increasingly confident that this is indeed the case. Change the code as following.

private boolean identifiedLinksHasKey(String linkKey){
       synchronized(Parser) {
            return Parser.identifiedLinks.containsKey(linkKey);
        }
}

private void putToIdentifiedLinks(String key, TreeSet<String> aset){     
    synchronized(Parser) {    
        Parser.identifiedLinks.put(key,aset);
    }
}

I haven't tried this code myself, and I'm not 100% sure whether it's possible to use a class (Parser) rather than an object to lock on. If this doesn't work, just pick any (single) object that's accessible from both threads / instances.

Upvotes: 3

user215054
user215054

Reputation:

Could it be that you have involved files as objects with guaranteed unique identity ? If you rely on it, say, you expect that object, representing file is guaranteed to be globally unique in memory. It will work until uniqness will be violated.

The breach in uniqness can come from operating system API. It is known for Windows (but rarely is well understood by people coming from Unix for example), that file handle of file created is not the same file handle of file just being found and opened through findFirst/findnext.

Consider file API in operating system as just a communication API to very remote system with no guarantee of cause and consequence. If you create file, it does not mean you can immediatelly find it, if you delete file, it may mean you will possibly still find it afterwards. etc.

Upvotes: 0

Steve Emmerson
Steve Emmerson

Reputation: 7832

I suspect that the identifiedLinksHasKey() and the putToIdentifiedLinks() methods are being executed by two different instances of the bgp.parser.Entry class, in which case the synchronized won't work.

Upvotes: 1

J-16 SDiZ
J-16 SDiZ

Reputation: 26910

compare these two:

bgp.parser.Entry.putToIdentifiedLinks(Entry.java:297) - locked <0x00000000853f2020>
bgp.parser.Entry.identifiedLinksHasKey(Entry.java:281) - locked <0x00000000853f00e0>

They are holding different lock. The synchronized keyword lock over the object instance. (i.e. If you create two object Object a=new Object(); Object b=new Object();, locking the in a won't affect b)

Upvotes: 7

corriganjc
corriganjc

Reputation: 690

If Parser is a singleton class or a static member of the Entry class, then the synchronization of the methods will not work as it only protects member variables of the Entry object. Static members will not be protected by that scheme. Your best bet is, probably to make the identifiedLinks member of the Parser class be a ConcurrentHashMap.

Upvotes: 0

Related Questions