Reputation: 9962
I've noticed something very strange yesterday. It seems that two threads are entering two synchronized blocks locking on the same object at the same time.
The class (MyClass
) containing the relevant code looks similar to this:
private static int[] myLock = new int[0];
protected static int methodA(final long handle, final byte[] sort) {
synchronized (myLock) {
return xsMethodA(handle, sort);
}
}
protected static int methodB(final long handle) {
synchronized (myLock) {
return xsMethodB(handle);
}
}
I created a thread dump of my application running the above class and was very surprised as I saw this:
"http-8080-136" daemon prio=10 tid=0x00000000447df000 nid=0x70ed waiting for monitor entry [0x00007fd862aea000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.MyClass.methodA(MyClass.java:750)
- locked <0x00007fd8a6b8c790> (a [I)
at com.SomeOtherClass.otherMethod(SomeOtherClass.java:226)
...
"http-8080-111" daemon prio=10 tid=0x00007fd87d1a0000 nid=0x70c8 waiting for monitor entry [0x00007fd86e15f000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.MyClass.methodB(MyClass.java:991)
- locked <0x00007fd8a6b8c790> (a [I)
at com.SomeOtherClass.yetAnotherMethod(SomeOtherClass.java:3231)
...
(I changed the class and method names for the case of simplicity, so don't get confused by the silly names.)
It seems that thread http-8080-136 and http-8080-111 have both acquired the lock on myLock
. It is the same object as the object address is the same: 0x00007fd8a6b8c790
. The Java Runtime Specification says this about the synchronized
keyword:
A synchronized statement acquires a mutual-exclusion lock (§17.1) on behalf of the executing thread, executes a block, then releases the lock. While the executing thread owns the lock, no other thread may acquire the lock. [The Java Language Specification, 14.19]
So how is this even possible?
There are another 44 threads in the thread dump "waiting" for the lock. This is how it looks like if a thread is waiting:
"http-8080-146" daemon prio=10 tid=0x00007fd786dab000 nid=0x184b waiting for monitor entry [0x00007fd8393b6000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.MyClass.methodC(MyClass.java:750)
- waiting to lock <0x00007fd8a6b8c790> (a [I)
at com.SomeOtherClass.yetAnoterMethod2(SomeOtherClass.java:226)
Upvotes: 7
Views: 837
Reputation: 9962
I've asked the same question on the hotspot-dev mailing list and received a very goot answer from Christopher Phillips:
Hi Eduard
I think its the thread dump that is misleading.
If you really think that the 2 are in the lock simultaneously you should probably get a gcore (which is externally consistent).
The state you see "waiting for monitor entry" is actually MONITOR_WAIT which can represent the following code before actual acquisition of a hot lock : (also see OSThreadContendState in osThread.hpp) called from: src/share/vm/runtime/synchronizer.cpp
3413 OSThreadContendState osts(Self->osthread());
3414 ThreadBlockInVM tbivm(jt);
3415
3416 Self->set_current_pending_monitor(this);
3417
3418 // TODO-FIXME: change the following for(;;) loop to straight-line code.
3419 for (;;) {
3420 jt->set_suspend_equivalent();
3421 // cleared by handle_special_suspend_equivalent_condition()
3422 // or java_suspend_self()
3423
3424 EnterI (THREAD) ;
3425
3426 if (!ExitSuspendEquivalent(jt)) break ;
3427
3428 //
3429 // We have acquired the contended monitor, but while we were
3430 // waiting another thread suspended us. We don't want to enter
3431 // the monitor while suspended because that would surprise the
3432 // thread that suspended us.
Chris
Upvotes: 4
Reputation: 3454
They haven't acquired lock, otherwise you would see xsMethodA or xsMethodB in a stacktrace.
Upvotes: 0
Reputation: 910
I think the relevant information is: "waiting for monitor entry", which is the same for both threads. Since both threads (in the thread dump) are marked deamon threads, I guess there must also be a main-thread running at the same time. Is it possible that the main-thread is the current monitor owner who blocks the other two threads?
Upvotes: 0
Reputation: 10772
How was the thread dump taken? If the threads were not paused the lock ownership could have changed between dumping one thread and the next.
Upvotes: 1