|
|
|
|
We said that, for a given thread that has already acquired the lock on a monitor, monitors are reentrant. However, if two (or more) threads compete for the same two (or more) resources, there is the possibility of deadlock, unless measures are taken to prevent it. For example, imagine that we're writing a program to transfer funds from one bank account to another, and we want to ensure that we have no problems when we are accessing accounts from different threads. Here's a possible program to do that:
But when you run the program, it outputs the following: Thread A: Getting balance from Account 1 Thread B: Getting balance from Account 2 Thread A: Balance from Account 1 = 10000 Thread B: Balance from Account 2 = 30000 and then stops. What's happening? Well, if you're running the program from a regular console window (an MS-DOS window on Microsoft Windows), using the java program (not jre), you can force a stack dump if you set the keyboard focus to the console window and press the proper keystroke combination:
and you will get output that looks something like this (this one was generated on Microsoft Windows NT): Full thread dump:
"Thread B" (TID:0x133d0f0, sys_thread_t:0xd26150, Win32ID:0x14b, state:MW) prio=5
threads.TransferFundsThread.transferFunds(Deadlock.java:70)
threads.TransferFundsThread.run(Deadlock.java:55)
"Thread A" (TID:0x133d110, sys_thread_t:0xd26210, Win32ID:0x15e, state:MW) prio=5
threads.TransferFundsThread.transferFunds(Deadlock.java:70)
threads.TransferFundsThread.run(Deadlock.java:55)
"SymcJIT-LazyCompilation-0" (TID:0x133cf58, sys_thread_t:0xd269c0, Win32ID:0x141, state:CW) prio=2
SymantecJITCompilationThread.run(JITcompilationthread.java, Compiled Code)
"SymcJIT-LazyCompilation-PA" (TID:0x133cf20, sys_thread_t:0xd251f0, Win32ID:0x158, state:CW) prio=10
java.lang.Object.wait(Object.java:307)
SymantecJITCompilationThread.run(JITcompilationthread.java, Compiled Code)
"Finalizer thread" (TID:0x1339088, sys_thread_t:0xd1c670, Win32ID:0x145, state:CW) prio=2
"main" (TID:0x13390b0, sys_thread_t:0xd1b8b0, Win32ID:0x14f, state:CW) prio=5
Monitor Cache Dump:
threads.Account@133D130/1429100: owner (0x7ffd9000, 1 entry)
threads.Account@133D148/14290B8: owner (0x7ffda000, 1 entry)
Registered Monitor Dump:
SymcJIT Method Monitor: <unowned>
SymcJIT Method List Monitor: <unowned>
SymcJIT Lock: <unowned>
Thread queue lock: <unowned>
Waiters: 1
Name and type hash table lock: <unowned>
String intern lock: <unowned>
JNI pinning lock: <unowned>
JNI global reference lock: <unowned>
BinClass lock: <unowned>
Class loading lock: <unowned>
Java stack lock: <unowned>
Code rewrite lock: <unowned>
Heap lock: <unowned>
Has finalization queue lock: <unowned>
Finalize me queue lock: <unowned>
Waiters: 1
Monitor registry: owner (0x7ffd8000, 1 entry)
For a detailed explanation of this output, see An Introduction to Java Stack Traces. However, here's a quick synopsis: The possible thread states are:
and you'll note that Thread A and Thread B are both in state: MW -- monitor wait. The thread stack trace shows where the threads are -- both threads are at the same point in their respective code -- both are attempting to acquire a lock on their respective m_to objects. Can you explain what's happening? Where is the problem? How can we solve it? As you can see, when you're dealing with multiple threads, you have to be aware of the possibility of deadlock, and try to avoid that.
|
| The page was last updated February 19, 2008 |