Java Forum / General / December 2005
deadlocks
ndxp@hotmail.com - 08 Dec 2005 06:32 GMT I need to know if there are any thumb rules which i need to follow in order to avoid deadlocks in thread.
thanks
Niels Dybdahl - 08 Dec 2005 09:37 GMT > I need to know if there are any thumb rules which i need to follow in > order to avoid deadlocks > in thread. Here are a couple: - Only update the user interface from one thread - Use synchronization features as little as possible - Try to avoid calling functions that might be modified from synchronized blocks (calling api functions that are welldefined and do not have any synchronized blocks are ok)
Niels Dybdahl
Thomas Weidenfeller - 08 Dec 2005 09:58 GMT > I need to know if there are any thumb rules which i need to follow in > order to avoid deadlocks > in thread. Not really. You have to know what you are doing. You have to understand threads, and you have to know what is going on in your source code (the different flows of control and their interdependencies, critical sections of code, access patterns to data, etc.).
Rules of thumb don't work very well with threading. Such rules basically mean "usually it works out if you do XYZ". However, something "usually working out" is not good enough when it comes to multi threading. The cases when it suddenly doesn't work out on that particular machine of that important customers in the middle of the night or at that important demo are the ones that hurt and are the ones which are extremely difficult to debug. The 1 out of 1000 failure which is almost impossible to reproduce in the lab.
/Thomas
 Signature The comp.lang.java.gui FAQ: ftp://ftp.cs.uu.nl/pub/NEWS.ANSWERS/computer-lang/java/gui/faq http://www.uni-giessen.de/faq/archiv/computer-lang.java.gui.faq/
Alun Harford - 08 Dec 2005 10:04 GMT >I need to know if there are any thumb rules which i need to follow in > order to avoid deadlocks > in thread. Know what you're doing. Prove that your program cannot deadlock. (Note that a simple solution to this is to ensure that a thread can only take out one lock at a time)
Alun Harford
Daniel Dyer - 08 Dec 2005 10:13 GMT >> I need to know if there are any thumb rules which i need to follow in >> order to avoid deadlocks [quoted text clipped - 5 lines] > > Alun Harford There are for conditions that must be true in order for a program to deadlock. By ensuring that at least one of these is not true you can avoid deadlocking.
http://en.wikipedia.org/wiki/Deadlock#Necessary_conditions
Dan.
 Signature Daniel Dyer http://www.dandyer.co.uk
ndxp@hotmail.com - 08 Dec 2005 10:20 GMT Proving a deadlock will not occur is quite hard for large complex system. I think we can probably minimize the possibility of a deadlock, but cannot completely avoid it. ( somebody tell me I'm wrong)
> >I need to know if there are any thumb rules which i need to follow in > > order to avoid deadlocks [quoted text clipped - 5 lines] > > Alun Harford Alun Harford - 08 Dec 2005 10:49 GMT > Proving a deadlock will not occur is quite hard for large complex > system. > I think we can probably minimize the possibility of a deadlock, but > cannot > completely avoid it. ( somebody tell me I'm wrong) For arbitrary systems, yes (deadlock detection is as hard as the halting problem). BUT: We make the system so we can use methods to ensure that deadlock cannot occur (just like we can prove that a particular program we make will halt). If you're making little programs, the method I gave is the easiest way (well actually I guess the easiest way is to not multithread, but that can be nasty if you're doing anything over a network). If you're making large, complex systems then you should know what you're doing.
Alun
Viator - 08 Dec 2005 10:18 GMT Read some theory of concurrent programming. You can find the same in any general purpose OS book.
Roedy Green - 08 Dec 2005 10:32 GMT >I need to know if there are any thumb rules which i need to follow in >order to avoid deadlocks >in thread. Use the Sun concurrent classes rather that doing synchronsation logic with primitives. See http://mindprod.com/jgloss/queue.html
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Roedy Green - 08 Dec 2005 10:32 GMT >I need to know if there are any thumb rules which i need to follow in >order to avoid deadlocks >in thread. the main one is always acquire resources in the same order.
 Signature Canadian Mind Products, Roedy Green. http://mindprod.com Java custom programming, consulting and coaching.
Stephen Kellett - 08 Dec 2005 12:32 GMT >the main one is always acquire resources in the same order. A more complete way of stating this is always acquire in the same order and always release in the reverse order to acquisition. If you get the releasing part wrong you can also have problems. Because of the way Java exposes the releasing part of the problem this is not an issue with Java, but can be with other languages (such as using the Win32 APIs directly for say Delphi, C++ or writing Java bytecode directly as the output for a given language).
Those of you writing multi-threaded code may be interested in Java Thread Validator, an automated deadlock detector for Java.
http://www.softwareverify.com
Stephen
 Signature Stephen Kellett Object Media Limited http://www.objmedia.demon.co.uk/software.html Computer Consultancy, Software Development Windows C++, Java, Assembler, Performance Analysis, Troubleshooting
Steve Horsley - 08 Dec 2005 15:52 GMT >> the main one is always acquire resources in the same order. > [quoted text clipped - 5 lines] > directly for say Delphi, C++ or writing Java bytecode directly as the > output for a given language). Can you explain why that might be? I can see that if a release call resulted in a hidden release-acquire-release sequence that this could be a problem - the hidden acquire might be out of order with other acquisitions. But I can't think why a clean release on its own might be problematic.
Steve
Stephen Kellett - 08 Dec 2005 18:36 GMT >Can you explain why that might be? I can see that if a release call >resulted in a hidden release-acquire-release sequence that this could >be a problem - the hidden acquire might be out of order with other >acquisitions. >But I can't think why a clean release on its own might be problematic. I'm not sure you understood what I meant - you may have, just your comment "clean release" makes me unsure, as I am not talking about a clean release. Two examples:
This is OK. (this is what I'd call a clean release if using that terminology).
1.acquire. 2.acquire. 3.acquire. 3.release 2.release 1.release
This is not OK.
1.acquire. 2.acquire. 3.acquire. 2.release <- mistake. 1.release <- mistake 3.release <- mistake
At some point another thread will be able to acquire 1 and 2 out of order with the acquisition of 3. This will lead to problems, most likely with some other thread that is using some or all of these locks.
I haven't got time to write you a code example that dies, but I've seen some pretty nasty results in Win32 multi-threading as a result of things like this.
Stephen
 Signature Stephen Kellett Object Media Limited http://www.objmedia.demon.co.uk/software.html Computer Consultancy, Software Development Windows C++, Java, Assembler, Performance Analysis, Troubleshooting
blmblm@myrealbox.com - 09 Dec 2005 11:34 GMT >>Can you explain why that might be? I can see that if a release call >>resulted in a hidden release-acquire-release sequence that this could [quoted text clipped - 28 lines] >order with the acquisition of 3. This will lead to problems, most likely >with some other thread that is using some or all of these locks. Umm ....
If the other thread is performing the same sequence of acquisitions (first 1, then 2, then 3), how is this a problem? The other thread isn't going to attempt to acquire 2 until it has 1.
What you're saying is at odds with what I've gathered from reading discussions of synchronization mechanisms in textbooks on operating systems. One of us is confused -- or possibly we don't mean the same thing by "acquire"??
>I haven't got time to write you a code example that dies, but I've seen >some pretty nasty results in Win32 multi-threading as a result of things >like this. Curious. Too bad you can't show us an example.
| B. L. Massingill | ObDisclaimer: I don't speak for my employers; they return the favor. Stephen Kellett - 09 Dec 2005 14:50 GMT In message <3vt8drF17bo52U5@individual.net>, blmblm@myrealbox.com writes
>>I haven't got time to write you a code example that dies, but I've seen >>some pretty nasty results in Win32 multi-threading as a result of things >>like this. > >Curious. Too bad you can't show us an example. The examples are usually very convoluted and not easy to demonstrate (or remember!) in a forum such as this. I'm not even sure I could write an example on demand. Its part of my memory of implementation of multi threaded systems and what caused them to fail.
Another issue not considered here is that releasing in the wrong order also has the following potential liablilities: o Possible performance drop as some locks will be held for longer than needed. o Possible data integrity problems as some locks will be released too early.
Anyway, as I initially said, it isn't an issue in Java unless you are writing bytecode directly.
Stephen
 Signature Stephen Kellett Object Media Limited http://www.objmedia.demon.co.uk/software.html Computer Consultancy, Software Development Windows C++, Java, Assembler, Performance Analysis, Troubleshooting
blmblm@myrealbox.com - 12 Dec 2005 07:44 GMT >In message <3vt8drF17bo52U5@individual.net>, blmblm@myrealbox.com writes >>>I haven't got time to write you a code example that dies, but I've seen [quoted text clipped - 7 lines] >example on demand. Its part of my memory of implementation of multi >threaded systems and what caused them to fail. Well, maybe you can talk a little more, in a general way, about the earlier part of my post. I'm a bit bothered by your claim in that it seems to directly contradict what I've read in general descriptions of deadlocks and synchronization mechanisms in operating systems textbooks -- bothered in that I wonder whether maybe I don't understand this as well as I thought.
Repeating from my previous post (quoted text yours):
>This is OK. (this is what I'd call a clean release if using that >terminology). [quoted text clipped - 18 lines] >order with the acquisition of 3. This will lead to problems, most likely >with some other thread that is using some or all of these locks. Umm ....
If the other thread is performing the same sequence of acquisitions (first 1, then 2, then 3), how is this a problem? The other thread isn't going to attempt to acquire 2 until it has 1.
>Another issue not considered here is that releasing in the wrong order >also has the following potential liablilities: >o Possible performance drop as some locks will be held for longer than >needed. Agreed on this one.
>o Possible data integrity problems as some locks will be released too >early. Not agreed on this one.
>Anyway, as I initially said, it isn't an issue in Java unless you are >writing bytecode directly. Maybe it would help if you could point me/us to an API for acquiring and releasing resources that *does* have the kind of problems you're talking about.
| B. L. Massingill | ObDisclaimer: I don't speak for my employers; they return the favor. Stephen Kellett - 12 Dec 2005 09:29 GMT In message <404o2bF18l4asU4@individual.net>, blmblm@myrealbox.com writes
>If the other thread is performing the same sequence of acquisitions >(first 1, then 2, then 3), how is this a problem? The other thread >isn't going to attempt to acquire 2 until it has 1. In that trivial example I posted it isn't a problem. As I said, the problems I've come up against were convoluted examples a lot more complex than several identical threads using the same locks. Most software I've worked on is not multiple identical threads working with the same locks. It is multiple different threads working with the same locks plus their own locks, some of which may be used by other threads. The trivial examples people use in these discussions (this one included) do not represent the real world.
>>o Possible data integrity problems as some locks will be released too >>early. > >Not agreed on this one. 1.acquire modify A 2.acquire modify B 3.acquire modify C 1.release at this point another thread can modify A <- potential damage 3.release 2.release
The potential damage is because the A should be protected. Since you've unlocked (1) in the wrong order A is not protected. 3 and 2 may still be held for quite a long time. But 3 and 2 are not protecting A.
In a trivial example where the locks are acquired immediately one after each other there is no problem. Real world examples usually have locks acquired in different functions. Thus if you release one too early you are exposing data that should be protected to potential manipulation from another thread.
>Maybe it would help if you could point me/us to an API for acquiring >and releasing resources that *does* have the kind of problems you're >talking about. Win32 EnterCriticalSection/LeaveCriticalSection and the equivalent java bytecode instructions for entering and leaving a monitor.
Stephen
 Signature Stephen Kellett Object Media Limited http://www.objmedia.demon.co.uk/software.html Computer Consultancy, Software Development Windows C++, Java, Assembler, Performance Analysis, Troubleshooting
blmblm@myrealbox.com - 12 Dec 2005 10:16 GMT >In message <404o2bF18l4asU4@individual.net>, blmblm@myrealbox.com writes >>If the other thread is performing the same sequence of acquisitions [quoted text clipped - 29 lines] >unlocked (1) in the wrong order A is not protected. 3 and 2 may still be >held for quite a long time. But 3 and 2 are not protecting A. I don't understand your example here. You have three locks, numbered 1, 2, and 3? What does 1 represent? from the fact that you acquire it just before modifying A, it would seem to be something you need to hold to modify A -- but then if the code modifies A after releasing this lock, then .... I wouldn't call that a problem with releasing locks in the wrong order so much as with failing to protect A by only modifying it while holding the associated lock. You would have the same problem if you released the three locks in the "correct" order, but modified A after releasing lock #1, wouldn't you?
>In a trivial example where the locks are acquired immediately one after >each other there is no problem. Real world examples usually have locks [quoted text clipped - 8 lines] >Win32 EnterCriticalSection/LeaveCriticalSection and the equivalent java >bytecode instructions for entering and leaving a monitor. The first Google hit for the former is this ....
http://msdn.microsoft.com/library/en-us/dllproc/base/entercriticalsection.asp
from which it's not obvious why the problem you describe occurs.
I think we may have to leave this as an unsolved mystery (from my point of view), since my guess is that neither of us has time to pursue it the depth that would be required.
| B. L. Massingill | ObDisclaimer: I don't speak for my employers; they return the favor. Stephen Kellett - 12 Dec 2005 15:11 GMT In message <4050v7F18b3i1U1@individual.net>, blmblm@myrealbox.com writes
>I don't understand your example here. You have three locks, numbered >1, 2, and 3? Yes.
>What does 1 represent? 1 represents a lock A lock that is required to modify various things. I happened to choose a simple example with just one variable A.
>from the fact that you acquire >it just before modifying A, it would seem to be something you need to >hold to modify A -- but then if the code modifies A after releasing >this lock, then .... I wouldn't call that a problem with releasing >locks in the wrong order so much as with failing to protect A by >only modifying it while holding the associated lock. Which is caused because you unlocked too early! This madness, you are agreeing with me whilst disagreeing :-). From what I have read in this discussion if you don't believe the release-in-reverse-order-to-acquisition rule you won't agree with the rest of what I've written.
I probably shouldn't have mentioned any of this at all as it doesn't apply to Java due to the way the language is constructed. We don't appear to be getting anywhere with this so best to leave it. It appears that you have come to the same conclusion.
Stephen
 Signature Stephen Kellett Object Media Limited http://www.objmedia.demon.co.uk/software.html Computer Consultancy, Software Development Windows C++, Java, Assembler, Performance Analysis, Troubleshooting
blmblm@myrealbox.com - 12 Dec 2005 17:01 GMT >In message <4050v7F18b3i1U1@individual.net>, blmblm@myrealbox.com writes >>I don't understand your example here. You have three locks, numbered [quoted text clipped - 16 lines] >Which is caused because you unlocked too early! This madness, you are >agreeing with me whilst disagreeing :-). But the "too early" is "too early relative to modifying A", not "too early relative to releasing other locks." If you released all three locks in the order you think proper (reverse of acquisition order), and then modified A, you would have the same problem, no?
>From what I have read in this >discussion if you don't believe the >release-in-reverse-order-to-acquisition rule you won't agree with the >rest of what I've written. You're right. You haven't said anything that convinces me that there are safety problems caused by the order in which one releases locks.
>I probably shouldn't have mentioned any of this at all as it doesn't >apply to Java due to the way the language is constructed. We don't >appear to be getting anywhere with this so best to leave it. It appears >that you have come to the same conclusion. Pretty much. I'm troubled by the contradiction between what you say (which sounds like it's based on real-world experience) and what I understand to be true from textbook discussions of synchronization mechanisms, though, so I'm having trouble just dropping it.
So maybe one more comment, and a question.
The comment: I'm basing what I say not on the specifics of how Java performs locking and unlocking -- which I admit I do not know details of -- but on my understanding of synchronization mechanisms and deadlocks in general, more or less as learned from textbooks on operating systems.
The question: What's special about Java, such that order in which locks are released doesn't matter, where it does in other languages / APIs?
| B. L. Massingill | ObDisclaimer: I don't speak for my employers; they return the favor. Stephen Kellett - 12 Dec 2005 18:25 GMT In message <405omvF18s5avU1@individual.net>, blmblm@myrealbox.com writes
>The question: What's special about Java, such that order in which >locks are released doesn't matter, where it does in other languages / >APIs? In Java you have no control over the 'release' part. You only control the acquire. The release part is automatically handled by the scoping rules of the language. This ensures that in Java the release order is the reverse of the acquire order.
Or put another way, when you write the code in Java you are saying what you want done (synchronization) but you are letting the compiler decide how to implement it.
I've been trying to remember when these events happened in the hope I could remember the scenario. It was about 3 or 4 years ago. I've been involved in a lot of code since then. It doesn't surprise me that I can't remember the scenario in any detail. If I can remember it I will let you know. Or if I realise that I've conflated two separate but related events I'll also let you know.
Stephen
 Signature Stephen Kellett Object Media Limited http://www.objmedia.demon.co.uk/software.html Computer Consultancy, Software Development Windows C++, Java, Assembler, Performance Analysis, Troubleshooting
blmblm@myrealbox.com - 13 Dec 2005 08:15 GMT >In message <405omvF18s5avU1@individual.net>, blmblm@myrealbox.com writes >>The question: What's special about Java, such that order in which [quoted text clipped - 5 lines] >rules of the language. This ensures that in Java the release order is >the reverse of the acquire order. Oh, right, of course. Sorry -- I don't know what I was thinking, asking that question.
>Or put another way, when you write the code in Java you are saying what >you want done (synchronization) but you are letting the compiler decide [quoted text clipped - 6 lines] >let you know. Or if I realise that I've conflated two separate but >related events I'll also let you know. Fair enough! I'm sure there are things about which I also could say "you know, sometimes that goes wrong, but I can't remember the details of the experience that taught me that ...."
| B. L. Massingill | ObDisclaimer: I don't speak for my employers; they return the favor. ricky.clarkson@gmail.com - 13 Dec 2005 10:28 GMT Someone said that you could avoid multi-threading, but that this would be undesirable if using networking.
I don't know whether you can do everything with java.nio that you can with java.io, but surely that would solve that issue.
EIO - event-driven I/O [1] might also be a good way of doing things.
Effectively, using SwingUtilities.invokeLater and generally avoiding threading by breaking things up into manageable chunks, you are emulating threading. I don't know whether that's a good thing or a bad thing, but I know I do it.
[1] http://java.twistedmatrix.com/eio/
Stefan Joubert - 13 Dec 2005 02:15 GMT > Which is caused because you unlocked too early! This madness, you are > agreeing with me whilst disagreeing :-). From what I have read in this > discussion if you don't believe the > release-in-reverse-order-to-acquisition rule you won't agree with the > rest of what I've written. What rule is this? If lock 1 is guarding resource A then what difference does it make when you release it relative to other locks which are concurrently held? Isn't the real issue that of respecting the locking hierarchy that is in effect?
Stephen Kellett - 13 Dec 2005 10:20 GMT >> Which is caused because you unlocked too early! This madness, you are >> agreeing with me whilst disagreeing :-). From what I have read in this [quoted text clipped - 6 lines] >which are concurrently held? Isn't the real issue that of respecting >the locking hierarchy that is in effect? Please read the rest of the thread. We've come to dead halt on this discussion.
Stephen
 Signature Stephen Kellett Object Media Limited http://www.objmedia.demon.co.uk/software.html Computer Consultancy, Software Development Windows C++, Java, Assembler, Performance Analysis, Troubleshooting
Stefan Joubert - 13 Dec 2005 16:35 GMT >>> Which is caused because you unlocked too early! This madness, you are >>> agreeing with me whilst disagreeing :-). From what I have read in this [quoted text clipped - 11 lines] > > Stephen I've read the entire thread. You are very confused about concurrency issues as are most Java programmers I've encountered. You've come to a dead halt like your software is likely to on a multiprocessor machine.
Stephen Kellett - 13 Dec 2005 17:11 GMT >I've read the entire thread. You are very confused about concurrency >issues as are most Java programmers I've encountered. You've come to a >dead halt like your software is likely to on a multiprocessor machine. If that is how you start your conversation I can only guess where it will go. There is no point in continuing.
Stephen
 Signature Stephen Kellett Object Media Limited http://www.objmedia.demon.co.uk/software.html Computer Consultancy, Software Development Windows C++, Java, Assembler, Performance Analysis, Troubleshooting
Steve Horsley - 16 Dec 2005 00:52 GMT >> Can you explain why that might be? I can see that if a release call >> resulted in a hidden release-acquire-release sequence that this could [quoted text clipped - 34 lines] > > Stephen My apologies for the long delay in replying after asking a question.
I have read the read of the thread (to date) and haven't seen anything that persuades me that it is important to release in any particular order. I have read once that as long as you acquire locks in the same order (e.g. 1, 2, 3) there can be no deadlock, and this makes sense to me. I can see that in a sequence such as: 1 acquire 2 acquire 3 acquire 2 release 2 acquire <= ERROR the very last step is in error because it is acquiring 2 while it already has 3. This is out of order and can deadlock with a thread that wishes to acquire 2 and 3. But I really don't see any harm in releasing in any order you like.
I guess the question is moot in a java thread, because, as was pointed out, java's use of synchronised blocks and methods enforces releasing in inverse order to locking because multiple locks MUST be in nested blocks. Since the text I read about acquiring locks in order was talking about java, there was no need for it to discuss the release order, so I may be missing some concept that is important for other languages.
Steve
Stephen Kellett - 16 Dec 2005 18:11 GMT >I have read the read of the thread (to date) and haven't seen anything >that persuades me that it is important to release in any particular >order. I said in a previous post that I would followup if I remembered any details and if in doing so I would also correct myself if I had conflated any of my memories.
Your post reminded me of something and then a few hours later I had a recollection of most of what my original posting. Hence this posting.
>I have read once that as long as you acquire locks in the same order >(e.g. 1, 2, 3) there can be no deadlock, Yes, I agree with this.
>and this makes sense to me. I can see that in a sequence such as: >1 acquire [quoted text clipped - 5 lines] >already has 3. This is out of order and can deadlock with a thread that >wishes to acquire 2 and 3. This is what triggered my memory of events. We had been working on a deadlock bug that involved recursive entry into a function that acquired a lock. Someone had move a lock release to make it out-of-order (as I have phrased it and as you show above if you can imagine your second acquire happening inside the recursive function I mention) and weeks later we had a deadlock bug that took some time to identify (and which was as I said rather convoluted due to the recursive nature of events and awkwardness of repeating the failure). The fix was to move the lock release back to its rightful place and make any necessary adjustments.
At the time we realised that the code wouldn't have failed if the locks involved in the original code and the recursive code had been released in reverse order so this became a rule of thumb, which again in my mind had turned itself into a hard and fast rule.
As you can see, as time passes both events merge and you have a conflation of events.
>But I really don't see any harm in releasing in any order you like. Yes. I agree with this. This was my mistake. This won't affect deadlocks. Releasing in any order may harm performance, depends upon your app.
>I guess the question is moot in a java thread, because, as was pointed Yes, I dived in headfirst into a cow pat of my own making. Anyway, it doesn't hurt to be honest about an honest failure of memory and it does hurt not to correct any incorrect assertions thus made. I'm not sure if you were the original poster I was chatting with as my newsreader has expired all the posts. Anyway I hope that sets things straight.
Stephen
 Signature Stephen Kellett Object Media Limited http://www.objmedia.demon.co.uk/software.html Computer Consultancy, Software Development Windows C++, Java, Assembler, Performance Analysis, Troubleshooting
blmblm@myrealbox.com - 17 Dec 2005 14:05 GMT [ snip ]
>>and this makes sense to me. I can see that in a sequence such as: >>1 acquire [quoted text clipped - 37 lines] >you were the original poster I was chatting with as my newsreader has >expired all the posts. Anyway I hope that sets things straight. I'm one of the people you were chatting with earlier, and .... Oh, this now makes much better sense. So would it be accurate to sum up as "the real problem was that the code was acquiring locks in the wrong order, but this was obscured by recursion and general code complexity, and the easiest fix involved making it standard practice to release locks in the opposite order in which they were acquired"?
That seems reasonable to me, and consistent with what I (think I) know about synchronization mechanisms.
Glad we seem to have cleared this up!
| B. L. Massingill | ObDisclaimer: I don't speak for my employers; they return the favor. Steve Horsley - 22 Dec 2005 16:42 GMT > I'm one of the people you were chatting with earlier, and .... Oh, > this now makes much better sense. So would it be accurate to sum [quoted text clipped - 7 lines] > > Glad we seem to have cleared this up! Yup. And I have to agree, knowing the order that locks are taken in can be very difficult. Java's nested blocks approach probably helps simplify it quite a bit, because you can't just call an acquire() function wherever you like.
Steve
Thomas Hawtin - 08 Dec 2005 19:25 GMT > I need to know if there are any thumb rules which i need to follow in > order to avoid deadlocks > in thread. First off, it is important that you know what you application is doing with respect to threads. Adding a few synchronized keywords randomly may stop the odd problem, but it is not a viable solution.
Don't synchronise at all.
The easy, yet high performance solution. A number of approaches: Require that everything is run in one thread (thread hostile, like Swing). Require that the client take care of synchronisation/single threading (thread agnostic). Make your objects immutable (technically you require 1.5 and need to declare fields final).
Keep synchronised blocks as small as possible.
Generally copy out what you need, then let go of the lock. Avoid calling all but the most well understood functions from within the block. In particular do not call callback methods while holding a lock.
Synchronise in a particular order
If you must nest synchronisations, make sure acquire the locks in a particular order. This may be on the basis of type or another property of the objects.
There are some tricky situations. For instance binary operators.
Consider StringBuffer.append(StringBuffer). It would probably be a bug on the part of the client code in this case, but you can deadlock with StringBuffers attempting to append to each other. a.append(b) in one thread, and b.append(a) in another.
A general approach is to use a global lock. Synchronize to a static around all binary operations, then synchronize onto operands in whatever order. Obviously this can cause hideous problems in code that makes extensive use of threads. To be avoided for server applications.
private static class Lock { } // Make thread dumps more readable. private static final Object GLOBAL_LOCK = new Lock(); public StringBuffer append(StringBuffer text) { if (text == null) return appendNull(); synchronized (GLOBAL_LOCK) { synchronized (this) { synchronized (text) { super.append(text); } } } return this; }
Another approach for StringBuffer.append is to copy out the contents. This is the copy-out advice from above. So:
public StringBuffer append(StringBuffer text) { // toString is done under lock. String str = text==null ? NULL_STRING : text.toString(); synchronized (this) { super.append(str); } return this; }
A third approach is to attempt to order the locking. 99.999% of the time Object.hashCode (i.e. System.identityHashCode) will give different values for a pair of Objects. In the unlikely event of a tie, we can use a fallback technique.
public StringBuffer append(StringBuffer text) { if (text == null) return appendNull(); int thisHash = this.hashCode(); int textHash = text.hashCode(); final StringBuffer firstLock; final StringBuffer secondLock; if (thisHash < textHash) { firstLock = this; secondLock = text; } else if (thisHash > textHash) { secondLock = this; firstLock = text; } else { assert thisHash == textHash; // Damn - cop out. return append(text.toString()); } synchronized (firstLock) { synchronized (secondLock) { super.append(text); } } return this; }
Tom Hawtin
 Signature Unemployed English Java programmer http://jroller.com/page/tackline/
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|