Granny's Programming Pearls
"inside of every large program is a small program struggling to get out"
JavaRanch.com/granny.jsp
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Blocks synchronized, but without wait() or notifyAll() methods. Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Spring in Action this week in the Spring forum!
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "Blocks synchronized, but without wait() or notifyAll() methods." Watch "Blocks synchronized, but without wait() or notifyAll() methods." New topic
Author

Blocks synchronized, but without wait() or notifyAll() methods.

Wilder C Rodrigues
Ranch Hand

Joined: May 03, 2003
Posts: 107
Hi,
I used synchronized blocks in my projeject and it is making a good job. But I never call wait() or notifyAll() methods. If the user attemps to lock a record locked an exception is thrown. I treated this exception and the user sees a warning message in a dialog box.
What do you think about that?
Thanks again,
Wilder


SCEA Part I, SCAJ, SCPJ, SCDJ, SCWCD, SCBCD, SCMAD<br /> <br />"The significant problems we face can not be solved at the same level of thinking we were at when we created them." - Albert Einstein
Jim Yingst
Wanderer
Sheriff

Joined: Jan 30, 2000
Posts: 18671
What do your instructions say should happen if the user calls lock on a record which is locked by another user?


"I'm not back." - Bill Harding, Twister
Wilder C Rodrigues
Ranch Hand

Joined: May 03, 2003
Posts: 107
Say that:
Any attempt to lock a resource that is already locked should cause the current thread to give up the CPU, consuming no CPU cycles until the desired resource becomes available.
Philippe Maquet
Bartender

Joined: Jun 02, 2003
Posts: 1872
Hi Wilder,
Any attempt to lock a resource that is already locked should cause the current thread to give up the CPU, consuming no CPU cycles until the desired resource becomes available.

It means that you must wait() and notifyAll() (or at least notify() depending on your design).
I used synchronized blocks in my projeject and it is making a good job. But I never call wait() or notifyAll() methods. If the user attemps to lock a record locked an exception is thrown. I treated this exception and the user sees a warning message in a dialog box.

You fullfil an automatic failure condition. Please don't upload it !
Best,
Phil.
Manoj Dixit
Ranch Hand

Joined: Sep 13, 2003
Posts: 31

Any attempt to lock a resource that is already locked should cause the current thread to give up the CPU, consuming no CPU cycles until the desired resource becomes available.

Hi,
I don�t think there is any way to implement above specification, which guarantees that thread will come up only when lock is released.
Consider following example:
Thread1 just locked recNo1.
Thread2 comes and lock recNo2.
Now Thread3 comes and tries to lock recNo1, but it is locked by Thread1 so goes in waiting period.
Now, Thread2 unlock recNo2 and notify (notifyAll). In such situation OS may again put Thread3 to run (assume my O.S is dump and there are other threads available to run).

The point here I am trying to make that, the waiting thread gives up CPU time for that period but again come up before the lock actually gets unlocked on desired recNo. So there is there any way that we can specifically invoke specific thread.
Correct me if I am wrong (and probably I am).
Regard�s
Manoj.
Bharat Ruparel
Ranch Hand

Joined: Jul 30, 2003
Posts: 493
Hello Gents,
I think that you need to think of logical record locking and physical read/write locks. Moreover, they need to be thought together as a unit.
Logical record locking is achieved by using the services provided by lock, unlock, and islocked methods of the Data class. We must use the functionality provided by the wait, notifyAll methods of the Object class to achieve this. What exactly you synchronize on is a variable that depends on what data structure you use and under what scope, i.e., is it a unique instance of Data class per client scheme or only one instance of the Data client.
Physical locks or synchronization is necessary to make sure that the records/fields being read/written by the file-pointer are read/written atomically. This is done (or at least I have done) by synchronizing on a singleton instance of the file-pointer. You don't want more than one instance of the file-pointer (or make it static) being used to read and write.
If you think of it in this manner than it becomes clearer. I also got a better understanding of the logical record locking when I started testing my implmentation using multiple clients. Use the new JDK1.4.1's logging facility judiciously to see for yourself how this works. Seeing is believing.
Regards.
Bharat


SCJP,SCJD,SCWCD,SCBCD,SCDJWS,SCEA
Manoj Dixit
Ranch Hand

Joined: Sep 13, 2003
Posts: 31
Hello Bharat,
I know it's logically and physically ( for RAF) works great.
But in case of CPU we can't be sure. So just forget about later(CPU)thing.
Is that right?.
Regard's
Manoj.
Bharat Ruparel
Ranch Hand

Joined: Jul 30, 2003
Posts: 493
Hello Manoj,
Your quote above:

Any attempt to lock a resource that is already locked should cause the current thread to give up the CPU, consuming no CPU cycles until the desired resource becomes available

This is what the "wait()" method does. They couldn't have been clearer in defining what they want in the lock method.
Regards.
Bharat
Philippe Maquet
Bartender

Joined: Jun 02, 2003
Posts: 1872
Hi Manoj,
Correct me if I am wrong (and probably I am).

You aren't. You are right for most of the lock implementations I've seen here around. Each time a record is unlocked and the waiting threads are awoken by a notifyAll() on some global locks container acting as a monitor, all waiting threads (maybe but one) consume a few CPU cycles just for ... nothing. And you cannot use notify() in that context, because the awoken thread will not necessarily be the one which is interested in the record you just unlocked. I think that if the above specification had to be strictly marked, there are a very few people around here who would have a chance to pass ... Also notice that they kindly used the word "should" instead of the ugly "must" one.
Now even if I don't deserve any credit for it, your remark doesn't apply to my own implementation : as waiting threads wait on individual lock objects (thus not on their container), and are nicely FIFO-ordered in a LinkedList, they awake only when the record is free for locking and they are the next waiting thread in the list, so actually and strictly consuming no CPU cycles until the desired resource becomes available.
Mmh... I should note that in my design choices and claim a bonus for it : as people get 80/80 points for locking without strictly fulfilling the instructions, sorry but I deserve at least 90/80 ! (I was kidding).
Best,
Phil.
Manoj Dixit
Ranch Hand

Joined: Sep 13, 2003
Posts: 31
Hi Philippe,
I am glad you replied and you hit the correct point whcih I was thinking.
I need your opinion.
I am almost done with my assignment(coding part, this is what I think).
I have implemented locking mechanism same like most of other folks ( waiting on Vector and again notifying).
Yesterday I re- read instructions and thought I am wrong ( I am ).
So what I am thinking:
Record Object with instance variable recNo and cookie.
I will store it into vector and instead of waiting on Vector I will put thread waiting on Vector(i).wait() (where i is Record object).
Again notifying same thing Vector(i).notify and remove that Record object from vector. ( I love vector, so please no Array[]).
What you think is it ok to do changes at this time and will this solution work.
Please comment.
Regard's
manoj.
Philippe Maquet
Bartender

Joined: Jun 02, 2003
Posts: 1872
Hi Manoj,
I am glad you replied and you hit the correct point whcih I was thinking.

Your point was correct but not that much important IMO.
I need your opinion.
I am almost done with my assignment(coding part, this is what I think).
I have implemented locking mechanism same like most of other folks ( waiting on Vector and again notifying).
Yesterday I re- read instructions and thought I am wrong ( I am ).

You're a little wrong with a very strict interpretation of the instructions, but as most people (AFAIK, all but me here since june) do it that way and pass (many of them with the maximum possible score), it seems to me that it's a fake issue.
Before I comment your proposed new solution, I'd like to comment what I think is a much bigger issue :
(...) (waiting on Vector and again notifying) (...) ( I love vector, so please no Array[]).

Both Vector and ArrayList ares Lists. You may just see Vector as an old-fashioned thread-safe ArrayList. And it brings two questions :
  • Is List the best collection type for the purpose ?
  • Even if you reply "yes" to question 1., do you need a thread-safe List ?


  • In your current implementation, answer to question 2 is definitely "no", as all threads accessing it will have to synchronize on it anyway to get notified.
    Question 1 is more interesting. Whatever you put in your Vector, how do you access it ? For sure not by recNo (not seriously applicable). I guess that you use a mix of the Vector.contains(), Vector.indexOf() and Vector.get() methods, performing linear searchs.
    If you use a Vector (no key-value pair), it could be replaced in 5 minutes by a HashSet, with a big plus in terms of theoretical performance. OK, you could reply that "performance is not an issue for this assignment", but I remember that one of our SCJP exam objectives was to be able to choose the right collection in a given context. So in the SCJD context, there is no good reason for your grader not to pay attention to such a design choice. Many people recently lost points in locking. As they hopefully tested their solution carefully before uploading (quite simple to do), we may suppose that their solution worked well. So I guess that the lost points may come from such a collection misuse.

    Record Object with instance variable recNo and cookie.
    I will store it into vector and instead of waiting on Vector I will put thread waiting on Vector(i).wait() (where i is Record object).
    Again notifying same thing Vector(i).notify and remove that Record object from vector.

    By doing that, you should solve the little issue you mentioned in your previous post, as far as you use notify() here and not notifyAll(). But is it worth while ?
    Best,
    Phil.
    [ October 22, 2003: Message edited by: Philippe Maquet ]
    Jim Yingst
    Wanderer
    Sheriff

    Joined: Jan 30, 2000
    Posts: 18671
    Philippe: you're not the only one here doing record-level locking. Thinking back, it was that "consume no cycles" line that made me favor sync on the record in the first place; in subsequent discussions I had forgotten that initial requirement. Because practically speaking, there's little difference between "consume no cycles" and "consume very few cycles". So I agree that it's extremely unlikely that this particular requirement is enforced rigidly - but those of us who do follow it should draw attention to it in choices.txt, as it helps mitigate possible whini...errr, criticism about "overly complex" sync mechanisms. After all, we're just following the spec.
    Philippe Maquet
    Bartender

    Joined: Jun 02, 2003
    Posts: 1872
    Hi Jim,
    Mmh, it seems that we agree once more...
    Philippe: you're not the only one here doing record-level locking.

    Great ! I feel less lonely then.
    Thinking back, it was that "consume no cycles" line that made me favor sync on the record in the first place;

    From memory, that's what I thought too.
    Because practically speaking, there's little difference between "consume no cycles" and "consume very few cycles".

    Yes ! And probably no difference enough to justify any loss of points with the "consume very few cycles" solution. If it was the case, we'd know it here on the ranch anyway.
    So I agree that it's extremely unlikely that this particular requirement is enforced rigidly

    They couldn't IMO, because (on purpose ?!) they wrote "should" instead of "must" as I mentioned above. When I read "should" I think of some ideal implementation (ours ), while "must" lets me think of the ugly "automatic failure" situation.
    but those of us who do follow it should draw attention to it in choices.txt, as it helps mitigate possible whini...errr, criticism about "overly complex" sync mechanisms. After all, we're just following the spec.

    Good point. We'll not get the bonus I was kidding about, but it perfectly justifies our more complex locking design.
    Best,
    Phil.
    PS: "Philippe" is my official first name. But all my friends call me "Phil" (even the french-speakers). That's probaly because I like this forum so much that I sign "Phil" all the time for a while now. So feel free to call me ... as you you want.
    [ October 22, 2003: Message edited by: Philippe Maquet ]
    Philippe Maquet
    Bartender

    Joined: Jun 02, 2003
    Posts: 1872
    Hi Jim,
    If you agree with what I wrote above about the use of Vector, ArrayList (or any List BTW), it would be great if you could confirm it. I have not the weight you and Andrew may have on this forum and it would be a pity that Manoj would lose points in locking just because of my lack of personal conviction power ...
    Best,
    Phil.
    Jim Yingst
    Wanderer
    Sheriff

    Joined: Jan 30, 2000
    Posts: 18671
    I have not the weight you and Andrew may have
    You're saying we're fat?
    Re. "Phil" - yeah, I only hesitated to use "Phil" because I knew it was an appropriate nickname in America, but I wasn't sure about Belgium. Though now I see you do sign "Phil" reasonably often, so I suppose I should have noted that previously. Thanks for confirming.
    Re: Vector/List/HashMap: Well, there are several issues here, and I mostly agree with you, except my design is different enough to lead to a somewhat different answer.
    First though: Vectors are evil. Well, not really, but there's no good reason. Peter den Haan gives a nice listing of why here.In addition to those reasons, for SCJD there's the fact that we want to show Sun that we've been paying attention to what's been going on in the language during the last five years, and using Vector seems to say "I've never heard of the Collections framework". Use an ArrayList or LinkedList instead.
    As for the main question: I agree that iterating through a List looking for a particular entry is undesireable, and it makes more sense to use a HashTable instead of iterating. However, there are ways that using an List, specifically an ArrayList, can make sense, maybe evne more sense. The key is - what if the index used in the ArrayList corresponds to the associated record number? In that case, to find the locking info for a particular record, you don't iterate at all, you just use get(recNo). Which is even faster than using a HashMap. The down side is, if the only thing you're using the ArrayList for is info about locked records, then the ArrayList is probably much bigger than it needs to be. Because you might have 10000 records and only 10 of them are locked at a given time - but in order for the array index to match the record number, you need to have an ArrayList size of 10000 rather than 10. Which seems inefficient.
    However, some of us are using a full caching solution. I've got the complete data from all records in memory anyway, in an ArrayList. It really doesn't take that much memory, for the speed benefits I receive. (And if you have so many records that the memory is a problem, then I guarantee a non-cached solution will be really slow whenever find() is called.) So, once you've made the commitment to having one Record object in memory for every single record, locked or no, then it's pretty easy to put locking info in that same Record structure. And so now you've got a solution which uses an ArrayList and get() to access locking info, and is faster than HashMap. It just happens to take more memory.
    So, I would way - if you're doing IO for every record access, no cacheing, then a HashMap is the ideal structure for managing locking info. If you're doing full caching, ArrayList is the way to go. IMO, anyway.
    Philippe Maquet
    Bartender

    Joined: Jun 02, 2003
    Posts: 1872
    Hi Jim,
    I have not the weight you and Andrew may have
    You're saying we're fat?

    Mmh... How to translate that figurative use of weight in good english ?!
    Let me consult my french/english dictionary. Oh ! I now found :
    "Your posts as well as Andrew's ones carry a lot of weight, anyway much more than I can, so ..."
    "Andrew and you lend so much more weight to your posts, that ..."
    "As java-heavyweights, Andrew and you ..."

    Re. "Phil" - yeah, I only hesitated to use "Phil" because I knew it was an appropriate nickname in America, but I wasn't sure about Belgium. Though now I see you do sign "Phil" reasonably often, so I suppose I should have noted that previously. Thanks for confirming.

    You're right that it's not a common nickname in french. But I worked a few months in the US in '97 (in Santa Rosa near San Francisco) and all people there called me Phil. I liked it, so I kept the habit. Now I reassure you : I speaked Delphi much better than english ...
    The down side is, if the only thing you're using the ArrayList for is info about locked records, then the ArrayList is probably much bigger than it needs to be.

    That's why I wrote above : "Whatever you put in your Vector, how do you access it ? For sure not by recNo (not seriously applicable)".
    you need to have an ArrayList size of 10000 rather than 10. Which seems inefficient.

    That's what I meant. I didn't explain it because it seemed obvious to me. Now add a zero to the table size, you get a 100000 records table, still a "small" one, and it becomes a bit uglier.
    However, some of us are using a full caching solution. I've got the complete data from all records in memory anyway, in an ArrayList. It really doesn't take that much memory, for the speed benefits I receive. (And if you have so many records that the memory is a problem, then I guarantee a non-cached solution will be really slow whenever find() is called.) So, once you've made the commitment to having one Record object in memory for every single record, locked or no, then it's pretty easy to put locking info in that same Record structure. And so now you've got a solution which uses an ArrayList and get() to access locking info, and is faster than HashMap. It just happens to take more memory.

    Within your full-caching solution, of course your choice makes sense. You even save some memory (the one which would be used by the average-10-records HashMap).
    So, I would way - if you're doing IO for every record access, no cacheing, then a HashMap is the ideal structure for managing locking info. If you're doing full caching, ArrayList is the way to go. IMO, anyway.

    I fully agreed with your conclusion, just adding that a locks HashMap is justified when you implement partial caching (optional) as I did.
    Best,
    Phil.
    Bharat Ruparel
    Ranch Hand

    Joined: Jul 30, 2003
    Posts: 493
    Jim,
    That is a great analysis of when to use ArrayList v/s HashMap.
    Thanks.
    Bharat
    Manoj Dixit
    Ranch Hand

    Joined: Sep 13, 2003
    Posts: 31

    I have not the weight you and Andrew may have on this forum and it would be a pity that Manoj would lose points in locking just because of my lack of personal conviction power ...

    Hello Philippe,
    You have great convincing power. The great explanation you provided led me to think about issues which I wasn�t (Code review). Well, I dropped the idea of record level locking and sticking with, what I have. Because what I think, each day I will come up with new ideas (buggy). So the assignment will go for forever.
    About vector:
    When I started learning JAVA I used vector a lot (in school). So the mind-set was (not now, u changed) use vector for object storing.
    By the way I changed all code from vector to arrayList ( was simple one line ).
    Thanks a lot
    Regard�s
    Manoj,
    Jim Yingst
    Wanderer
    Sheriff

    Joined: Jan 30, 2000
    Posts: 18671
    Mmh... How to translate that figurative use of weight in good english ?!
    To be fair, your english was fine the first time; I was just teasing you. Also yes, it was clear that your advice about HashMap over ArrayList was referring to the non-caching or limited-caching scenario. But since you asked me, I chose to talk more about the design I used instead.
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Blocks synchronized, but without wait() or notifyAll() methods.