Originally posted by George Marinkovich:
Hi Satish,
What is it in your application design that you think might lead to a deadlock situation?
I do not see anything in the application that causes a deadlock. There are very few synchronized blocks(4-5) in the total Data class and all are synchronizing on the existingRecords(ArrayList) only and two other synchronized blocks which synchronize on the deletedRecords(ArrayList). That is it. No methods are synchronized. And yeah, I got blocks synchronized on lockedRecords in lock and unlock methods.
Note: There are no synchronized(hmmm...what do we call them?) inner blocks or OK. I give up..I will show it.
There are no blocks like either of them. Do you think its fine?
Originally posted by Satish Avadhanam:
I think you meant to say you don't have any nested synchronized blocks like those in the example you gave, right?
There are no blocks like either of them. Do you think its fine?
That sounds good but it wouldn't necessarily be so obvious. I would suggest you sit down with your code and trace what happens during a book operation, paying particular attention to when you enter a synchronized block and when you exit a synchronized block. For example, the first thing I do in a book operation is call lock(). The lock method enters a block synchronized on whatever and then it leaves the block. Then read is called. The read method enters a block synchronized on whatever and then it calls another method. This other method enters a block synchronized on something, etc. If you find that you're never entering nested synchronized blocks the you less to worry about than if you were using nested blocks.
George, I got a couple of questions regarding testing. I'm not aware of any tools like JUnit or others. Can you please guide me which one to use? Or is it ok if we test it on the grounds of Max's testing? I mean like his test programs.
Well JUnit is worth learning just for the sake of your future Java work, but you don't need to use it for this project if you don't have the time to learn it now. Yes, Max's testing harness is a very good starting point for you to develop your own multi-threaded test harness. If you want to take a look at the one I based on Max's testing harness you can look here:Topic: All of URLy Bird 1.1.3 about Junit test
Regards, George
SCJP, SCJD, SCWCD, SCBCD
George:
Seriously, I think a locking functionality that permits deadlock is inherently a seriously flawed implementation and you can expect to lose points if your implementation allows this to happen.
Originally posted by Philippe Maquet:
Hi Satish,
Even if most people here (AFAIK) think that dealing with deadlocks is overkill, I fully agree with George.
Anyway, it cannot hurt if you do it, I think.![]()
Yes Phil, I too thought the same after Geroge and you said, working on it now.
I basicaly see 4 solutions in that area:
1. What you are doing now: any client cannot own more than one lock at a time. Deadlocks are impossible, obviously.
This is my case, but still have some dead lock cases. Please see at the bottom.
2 & 3
For now, I think I will stick to condition -- each client cannot own more than one lock.
4. Data (or LockManager if you have one) detects deadlocks when they occur, and breaks a dealock by choosing a "looser" (typically the client who is claiming the new lock).
In my situation deadlocks are occuring for a different reason. Will detail below.
Critiques:
1. No dealock, but only "thanks" to a huge restriction in the use of the DBAccess interface as documented (OK poorly) by SUN, and I think such a restriction is not acceptable.
Phil, please tell that my locking mechanism has atleast one good/better quality![]()
2. The easier solution. And as I think that's what Ken did (and he got a perfect locking score) it is advisable I think.
Phil, are you saying that Ken allowed mulitple locks? I could'nt see that in his design. I have gone through Ken's locking again and will deatail it below.
3. Comparable to 2, with more work![]()
It seems that you don't want me to complete assignment soon...Just kidding.
4. The best solution IMO. No restriction on the use of the interface and deadlocks are broken in case they occur. BTW, 4 is not incompatible with 2.![]()
Maybe I will end up with this only Phil. I don't know. First I did'nt have any lock manager, locking is taken care in lock/unlock. Now, lock manager is added...and still issues. Will look at some more past posts on lock manager to get a good idea.
2. Am not dealing with crashed clients.
I also agree with George here, though it's so easy to handle (much easier than deadlock detection anyway), that it could be worthy to do it.
I have gone through some posts regarding this issue, but could'nt figure out exactly how to do. So will spend some more time reading and try to implement this also. I think WeakHashMap is one option. Am I right?
Regards,
Phil.
Locking
======
1. The implementation of the Services book method in ServicesImpl is the only user of the locking API.
2. I specified a contract in the Javadoc that calls for any potential users of the locking API to invoke lock/process/unlock as a sequence within the context of a single method call which guarantees it will happen within a single thread of execution.
3. When lock is invoked, a check is made to see if the Contractor already has been locked by another thread.
4. If it has, the current thread will wait until notified that it has been unlocked.
5. If not, a Lock object is created that has a reference to the current thread and it is put in the locking Map with the Contractor as the key.
6. The protected processing operation is performed and then the Lock is removed from the Map and destoyed by the unlock method call.
7. It is vital that any exception that occurs during processing is caught and rethrown after the Contractor has been unlocked.
8. Deadlock is prevented by specifying a locking order to be used by programmers.
1. CSRDataAdapter is the only user of locking mechanism. To be precise, only the book method uses the locking functionality here. Am providing only two methods in CSRDataAdapter -- book & find.
2. He also specified a contract. But you were saying that he did'nt mentioned any in your 2'nd point, right?
3. Same as 3 above.
4. Same as 4 above.
5. Instead of using the reference am using the Random.nextLong(). I think you know who gave this advice![]()
6. In unlock, it will be removed.
7. I think am stuck here with dead lock problem. Will explain below.
8. Will provide a locking order to follow, but I have to deal with 7.
In general, and keeping in mind that I don't know yet that my
code is free of dead-locks, I'd give the hint that update()
need not call lock() and unlock() at all.
Originally posted by Javini Javono:
Hi,
In general, and keeping in mind that I don't know yet that my
code is free of dead-locks, I'd give the hint that update()
need not call lock() and unlock() at all.
How did you came to this conclusion? I mean, the instructions clearly state:
// Modifies the fields of a record. The new value for field n
// appears in data[n]. Throws SecurityException
// if the record is locked with a cookie other than lockCookie.
Don't you think we need to use the protocol of lock/doSomething/unlock here?
The client is the one who uses lock() and unlock().
Do you mean CSR here? Am using server side locking and all locking is in adapter class only.
Thanks,
Javini Javono
[ March 19, 2004: Message edited by: Javini Javono ]
I'd give the hint that update()
need not call lock() and unlock() at all.
"creation in place," would need to grab a lock.
The client is the one who uses lock() and unlock().
Do you mean CSR here? Am using server side locking and all locking is in adapter class only.
Originally posted by Philippe Maquet:
Hi Don and Satish,
he means that lock() and unlock() shouldn't be called *from* update(). And that's right.
Oh! Then its ok.
Not the CSR but any object which is garanteed to be unique per client. BTW do you have one Data instance per client in your design?![]()
Yep, am having one instance per client. No static RAF.
Regards,
Phil.
Originally posted by Philippe Maquet:
Oops! I missed it, sorry.![]()
I'll read it now and reply a little later.
8. Deadlock is prevented by specifying a locking order to be used by programmers
5. If not, a Lock object is created that has a reference to the current thread and it is put in the locking Map with the Contractor as the key.
5. Instead of using the reference am using the Random.nextLong(). I think you know who gave this advice
![]()
About the crashed clients detection:
I have gone through some posts regarding this issue, but could'nt figure out exactly how to do. So will spend some more time reading and try to implement this also. I think WeakHashMap is one option. Am I right?
The issue in my design is like this:
1. Suppose update method has locked the record say.
2. In update I again check whether the record is present or not, if not throw RNFE.
3. The problem is the thread did'nt unlock record 100 and so other threads will be waiting like that.
4. Result deadlock
Originally posted by Philippe Maquet:
Hi Satish,
Does lockRecord() throw RecordNotFoundException like in my instructions?
Yes.
If it's the case, I don't understand how the issue you mention could happen, because as delete() cannot execute without a lock, it's impossible that a record is deleted by another thread in the middle of a lock() - update() sequence.
I think I did not explain the problem correctly. How exactly locking works is as deatailed below.
Now if it's not the case, let me know and we could see how to solve it.
Regards,
Phil.
[ March 20, 2004: Message edited by: Philippe Maquet ]
Originally posted by Philippe Maquet:
Hi Satish,
Indeed, if the key is not the recNo, how could a given client own more than one lock?
Good catch of you!
No no, the key is the recNo only Phil. And clients cannot own multiple locks in my design.
Regards,
Phil.
[ March 20, 2004: Message edited by: Philippe Maquet ]
Originally posted by Philippe Maquet:
Hi Satish,
Indeed, if the key is not the recNo, how could a given client own more than one lock?
Good catch of you!
No no, the key is the recNo only Phil. And clients cannot own multiple locks in my design.
Regards,
Phil.
[ March 20, 2004: Message edited by: Philippe Maquet ]
As I was testing for multiple clients, here's one scenario. BTW, the above sequence is called in try catch block in adapter.
Suppose T1, T2, T3 are the threads.
T1 wants to delete record 100.
T2 wants to delete record 100.
T3 wants to update record 100.
T1 locks the record.
T2 sees that the record is locked and waits.
T3 also waits to lock the record.
T1 deletes the record.
T1 notifies.
T2/T3 tries locks the record(Not existing).
In update/delete methods they throw RNFE.
So because of this, unlock is not called in the adapter(Poor design)
The result was deadlock.
Phil, the thread you pointed out, does it really talk about locking mechanism? Frankly I could not understand anything over there other than your first post with the lock manager code comparision and that is what is required
Thanks for that. I think the post you referred is mostly talking about efficiency on which collection class to use.
Am going through the idea of using lockmanager like you showed, but still
Lots of things to understand in there. Will try and post any questions if I have any.
When the thread waits on the object itself in the second synchronized block, it is taking away the lock on lockedRecords(outer synchronized object) with it. But if I don't use the outer synchronized block, then I cannot make sure that only one thread is testing the if/else statement. I cannot wait on two objects, is'nt it? So I was thinking about this problem for so much time and could'nt come up with a solution
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Originally posted by Andrew Monkhouse:
Hi Satish,
I agree with Don: having the nested synchronized code is a big mistake. I suspect you haven't tested this in a scenario where multiple threads are waiting for the same record - you will probably find that not only will they never wake up, but it will stop your entire server from processing any other records.
This was the reason I was worried about at first in this design.
(By the way - I recommend you set up such a test now, and prove to yourself that there is a problem. Then when you fix it, you will have a test to prove you have fixed it.)
Thanks for the tip Andrew. Will do maximum stress testing then.
Most candidates do not seem to go to this level of adherence to the specification - they simply allow threads to wake up whenever any lock is released. But it is possible to have a thread only wake up when the lock it is interested in is released, and you are nearly there.
I am particulary worried about the locing scores of 44/80. That is why I was trying to make it do exaclty record matching.
Hint: At present you are using the contents of lockedRecords as a marker for whether a record is locked or not. You are not using the contents for any other purpose. If the contents were some mutable object, then it would not have to be destroyed each time you unlock a record - just change it's contents. Can you think of whether that might help you?
Regards, Andrew
Originally posted by Philippe Maquet:
Hi Satish,
Sorry to be unable to pursue our interesting discussion about locking. I won't be able to follow this thread before thursday (it wouldn't be reasonable for compelling professional reasons) , but I'll come back soon.
![]()
Regards,
Phil.
[ March 23, 2004: Message edited by: Philippe Maquet ]
One question Andrew: In the above Hint you mentioned, is it "mutable object" or "Immutable object" you were saying?
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Dead-locks are avoided by following the locking order rules: always
lock LockManager, then lock MicroData.
Usually, of course, clients are
operating outside of MicroData, first using the lock manager, then calling
Data.someMethod() which in turn calls the appropriate methods in MicroData.
Originally posted by Don Wood:
Hi Javini,
especially when the thread goes to sleep holding the outer lock while waiting for the inner lock to become free?
Yeah this is a real issue as you cannot wait on two objects. So as long as you wait on the inner object, you obvioulsy are taking the lock of outer object with you. I'm just wondering is there anyway of "wait"ing on two objects? I mean to realease locks on both outer and inner objects. I could'nt think of a way of doing this. Threading Gurus have to shed some light on this issue![]()
[ March 24, 2004: Message edited by: Don Wood ]
//Therefore in the unlock method, I
// can notify on the object itself. I believe this satisfies the
//statement, don't waste CPU cycles while the record is locked
Originally posted by Philippe Maquet:
Hi Satish,
I have nothing to add to previous comments, and reading your last post, I think you're on the right track.
*But* do you really think that keeping the record-level-locking technique is worth while?
I am not sure Phil. I don't want to get surprised once I see the score that my locking did'nt get full marks because of that reason. So only sticking to the true meaning of the instructions.
Look at what I wrote here about it a few day ago.
Thanks Phil. I had a look at it.
Wouldn't be much easier (and as defendable) to use the solution mentioned as 1.2 in the Notification Issues thread?
Easier, yes. But I told you before only that am much worried about score.
Moreover, dead clients detection included, with the help of the technique you just mentioned?![]()
If I use 1.2 solution then dead client detection would be easy compared with what am doing now. But I really don't know if I want to change the locking and go to solution 1.2.
Regards,
Phil.
[ March 25, 2004: Message edited by: Philippe Maquet ]
get schwifty. tiny ad:
Smokeless wood heat with a rocket mass heater
https://woodheat.net
|