aspose file tools*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes NX: Data a singleton and no cache - trouble? Andrew  help if you can Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "NX: Data a singleton and no cache - trouble? Andrew  help if you can" Watch "NX: Data a singleton and no cache - trouble? Andrew  help if you can" New topic
Author

NX: Data a singleton and no cache - trouble? Andrew help if you can

Raymond Tanner
Greenhorn

Joined: Jan 09, 2004
Posts: 24

Your server must be capable of handling multiple concurrent requests, and as part of this capability, must provide locking functionality as specified in the interface provided above.

Do you satisfy this if you have the Data as a singleton, no cache, and all of your methods including your searches and reads are synchronized (lock and unlock of course are not synchronized because they have synchronized blocks). I mean yeah the server can handle multiple requests but it can only do one at a time because you can't take the chance of messing with the file handle (thus your searches/reads must also be synchronized).
This is what I have done and I don't want to change my entire design.
I could implement a cache but I always felt a cache was trouble and
pointless.
joe black
Ranch Hand

Joined: Dec 03, 2003
Posts: 103
I have the same design as you, except I don't have Data as a singleton since I can't see how I could have more than one instance, and so the Data class could be used in the future for multiple tables, and I have run many tests and its bulletproof.
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11526
    
100

Hi Raymond,
You might want to consider whether you need all those methods synchronized or not.
For example - the search method. The only part that needs to be synchronized is when it is physically reading from file (and probably you should be calling a common synchronized method for that). The remainder of the search method could remain unsynchronized which will allow multiple threads to run and allow better concurrency.
If you go through all the methods, you will probably find that there is very little that must be synchronized. Try and limit them so that you can get more concurrency in your application.
Regards, Andrew


The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Raymond Tanner
Greenhorn

Joined: Jan 09, 2004
Posts: 24
Yes, for my searches all I need to synch is the fetching of the data.
Much better.
joe black
Ranch Hand

Joined: Dec 03, 2003
Posts: 103
In the find(), what if you obtain a record count, then another thread runs which adds a new record, then your thread running find() resumes? The record count for the find() would now be invalid. I include obtaining the record count within the synchronized block as well.
[ January 10, 2004: Message edited by: Joe Black ]
Philippe Maquet
Bartender

Joined: Jun 02, 2003
Posts: 1872
Hi Joe,
After findByCriteria() completes and before reads are then performed, records may be updated, deleted and created anyway.
Best,
Phil.
joe black
Ranch Hand

Joined: Dec 03, 2003
Posts: 103
you're right. thanks phil.
Raymond Tanner
Greenhorn

Joined: Jan 09, 2004
Posts: 24
I had my entire read/search methods synched and now I am going to
take all of your advices and only synch on what is really necessary and
document the rest. - Thank YOU!!!
Would it make just as much sense and more clean to synch on "this"
(i.e. synchronized (this)) than on my handle to the file in my read
and search methods. Remember my Data class is a singleton. I am a little
confused over this. If I synchronize on my file handle I am afraid
of deadlock issues. Becuase then I could have a physical lock via
lock/process/unlock on my collection, a lock on a method (i.e. update is
synchronized so is delete) and then on my searches I would be locking
on the file handle, which by the way gets locked by my synchronized methods such as update and delete. Basically I don't know how to determine if a deadlock could occur. Yes I can test but that doesn't clear me from deadlock issues 100%.
[ January 11, 2004: Message edited by: Raymond Tanner ]
Raymond Tanner
Greenhorn

Joined: Jan 09, 2004
Posts: 24
help
joe black
Ranch Hand

Joined: Dec 03, 2003
Posts: 103
if you have a deadlock it could hang. if you do lock, update, unlock, how can you have a deadlock? lock and unlock are synch'd on the lockmap collection, and all your other methods that are sycnh'd will be synch'd on the raf, or you could synch on this if it's a singleton. if you don't have synch'd code in synch'd code u should be fine.
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11526
    
100

Hi Raymond,
Originally posted by Raymond Tanner:
Would it make just as much sense and more clean to synch on "this" (i.e. synchronized (this)) than on my handle to the file in my read and search methods. Remember my Data class is a singleton.

Practically I don't think it will make any difference. Choose whichever you feel will make the most sense to the person maintaining (or grading) your code in the future.
Personally I prefer to synchronize on the file handle - it is access to the file which needs to be synchronized, so to me it makes logical sense to use that as the mutex. But that is just personal preference.
Another thing is that by using the file handle, you are leaving the class instance mutex available for some separate synchronization mutex sometime in the future (not needed for this assignment though).

Originally posted by Raymond Tanner:
I am a little confused over this. If I synchronize on my file handle I am afraid of deadlock issues. Becuase then I could have a physical lock via lock/process/unlock on my collection, a lock on a method (i.e. update is synchronized so is delete) and then on my searches I would be locking on the file handle, which by the way gets locked by my synchronized methods such as update and delete. Basically I don't know how to determine if a deadlock could occur. Yes I can test but that doesn't clear me from deadlock issues 100%.

As Joe said - do you have some of those locks calling any other lock? Try and work through the various scenarios, seeing if you do have multiple mutex's being held simultaneously. If you do, then you have potential for deadlock. If you don't then you don't have the potential for deadlock. In my next post I will try and run through them myself, but you should try and work it out yourself before going on to the next post .
Regards, Andrew
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11526
    
100

Hi Raymond,
Did you work it out for yourself? Here's my attempt:
  • While owning a logical lock, you can:
  • Try to get another logical lock: deadlock possibility.
  • Try to get the mutex on the logical locks
  • Try to get the Data instance mutex (for update or delete methods)
  • Try to get the File handle mutex (for any file operation).
  • While owning the mutex on the logical lock, you can:
  • Try to grant / release a logical lock
  • While owning the mutex on the Data instance, you can:
  • Get the file mutex for working with the file
  • While owning the mutex on the file handle, you should not try to get any other mutex / logical lock.

  • [/list]
    As you can see, your lock requests all flow downwards (type A lock can get a type B lock, but type B lock cannot get a type A lock). You may own one lock (whether logical or mutex) and try and get another lock (either logical or mutex), and you should never get yourself into deadlock.
    Note: I made some assumptions about what your code is doing. If you can see a case where you own a lock and you can try to get another lock that I havent mentioned, then you need to look at whether that opens a deadlock situation.
    The exception was that you could own one logical lock and try to get another logical lock. If you allow this, then deadlock can occur. But that is outside your original question of whether to use the Data instance mutex or the file handle mutex: regardless of which you choose, the logical lock deadlock can still occur.
    Regards, Andrew
    [ January 12, 2004: Message edited by: Andrew Monkhouse ]
    Raymond Tanner
    Greenhorn

    Joined: Jan 09, 2004
    Posts: 24
    First off let me give both of you a BIG THANKS for helping me out.
    Locking is my weakest subject and I am so afraid of creating a deadlock
    scenario. If this message gives you a headache I am sorry, I know it gave
    me one.
    After thinking about it I think I am going to synchronize on this. But I have two questions:
    1. What do you mean by "if you don't have synch'd code in synch'd code u should be fine."
    I ask this because my Update and Delete are both fully synchronized and they
    call a synchronized method getRecord(). getRecord() manipulates the file handle indirectly because it checks to see if the record exists. After
    the call it returns to Update or Delete and then Update/Delete ALSO manipulates the file handle obviously to carry out the actual updating of
    the file. Other methods, such as my read call getRecord() also.
    Here is example code:
    1. getRecord():

    2. Delete (follows the lock/process/unlock contract)

    3. and finally my Read:

    Question 2. "As you can see, your lock requests all flow downwards (type A lock can get a type B lock, but type B lock cannot get a type A lock). You may own one lock (whether logical or mutex) and try and get another lock (either logical or mutex), and you should never get yourself into deadlock.
    I am confused on what exactly you mean and how to tell if my above code
    does this. Could you please give a little more explanation or use my code
    as an example?
    [ January 12, 2004: Message edited by: Raymond Tanner ]
    [ January 12, 2004: Message edited by: Raymond Tanner ]
    [ January 12, 2004: Message edited by: Raymond Tanner ]
    Terry Martinson
    Ranch Hand

    Joined: Oct 18, 2003
    Posts: 293
    Raymond - in your read code above, you do an explicit synchronized(this) within the synchronized method.
    My understanding is that by sychronizing the method, you are basically doing the same thing as synchronizing on "this".
    So, do you need both?
    Help, I'm a little confused on this locking stuff too!

    TJ


    SCJP, SCJD, SCWCD, SCBCD
    Raymond Tanner
    Greenhorn

    Joined: Jan 09, 2004
    Posts: 24
    Terry,
    This is true, but notice I only synchronize on the fetching of the data with this? So this is only locked up during the fetching of the data.
    Not during entire method which would occur if a synchronized the entire method.
    Get it?
    ray
    joe black
    Ranch Hand

    Joined: Dec 03, 2003
    Posts: 103
    Terry is right. You have the keyword synchronized in the method
    signature which is the same thing as sychronized(this){},
    so it is redundant.
    [ January 12, 2004: Message edited by: Joe Black ]
    Raymond Tanner
    Greenhorn

    Joined: Jan 09, 2004
    Posts: 24
    that was a mistake. My "read" should not have been synchronized. thats
    how I had it originally. I updated the post and it should look like this:

    thanks guys.

    Joe, what do you think?
    [ January 12, 2004: Message edited by: Raymond Tanner ]
    joe black
    Ranch Hand

    Joined: Dec 03, 2003
    Posts: 103
    Since your getRecord() method is already synchronized
    on this, the synchronized block in your read() method
    is also redundant. Just synch code that changes the
    raf file pointer.
    [ January 12, 2004: Message edited by: Joe Black ]
    Raymond Tanner
    Greenhorn

    Joined: Jan 09, 2004
    Posts: 24
    I have thought about it and I think I have it now.
    Basically all of my reads and searches are going to be left un
    synchronized because they call sychronized methods that synch on (this)
    to fetch the data. After the data has been fetched yes changes can take
    place but if the user tries to respond to something that is bad data
    in the end they will be caught by my validations in book/update/delete/.
    So the worst that could happen is an error message.
    Is this sounding better?
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11526
        
    100

    Hi Raymond,
    First, let me say that your latest post looks very good - it will certainly save you a lot of heartache.
    Now to some questions which may still be unanswered:
    Originally posted by Raymond Tanner:
    1. What do you mean by "if you don't have synch'd code in synch'd code u should be fine."

    Not my quote, but I will answer it anyway (but since it is not my quote, I may wrong).
    Joe is basically suggesting that as long as you only ever own one "lock" at any given time, you cannot ever get into a deadlock situation.
    He is right, however it does leave you unprepared if ever you do encounter a situation where you must own more than one lock at any given time.

    Originally posted by Andrew Monkhouse:
    As you can see, your lock requests all flow downwards (type A lock can get a type B lock, but type B lock cannot get a type A lock). You may own one lock (whether logical or mutex) and try and get another lock (either logical or mutex), and you should never get yourself into deadlock.
    Originally posted by Raymond Tanner:
    I am confused on what exactly you mean and how to tell if my above code
    does this. Could you please give a little more explanation or use my code
    as an example?

    Sorry about confusing you.
    What I suggest you do is write down what locks you can own, and what locks you can get while you own them. For example:
  • I own a lock on ObjectA, and while I own it, I can get a lock on ObjectB
  • I own a lock on ObjectB, and while I own it, I can get a lock on ObjectC or ObjectD
  • I own a lock on ObjectC, and while I own it, I cannot get any other locks
  • I own a lock on ObjectD, and while I own it, I cannot get any other locks


  • Can you see how I can only ever work down the list? Assume I start at point 2 - I can only progress to points 3 or 4. I can never go back to point 2 or up to point 1.
    Now for another example:
  • I own a lock on ObjectA, and while I own it, I can get a lock on ObjectB
  • I own a lock on ObjectB, and while I own it, I can get a lock on ObjectC or ObjectD
  • I own a lock on ObjectC, and while I own it, I can get a lock on ObjectB
  • I own a lock on ObjectD, and while I own it, I cannot get any other locks


  • Now I have a problem. In point 3, I can move up the list to point 2. And point 2 can move down the list to point 3. So we have the potential for a client to own the lock on ObjectB and trying to get the lock on ObjectC, while at the same time a different client owns the lock on ObjectC and trying to get the lock on ObjectB.
    In this last case, I have proved logically that there is potential for deadlock. I would either need to change my logic so that this potential is alleviated, or add deadlock prevention code to my application.
    Does this make sense?
    If so, take another look at my earlier post. I went through all the locks that I thought you had, and wrote down which locks I thought you might try and get. Using my guesses about what you had, I made up a couple of lists that only worked downwards. So I thought you would have been safe.
    ---
    As I mentioned in another thread - I strongly recommend you work out logically whether your code is safe from deadlocks (don't rely on just the test code that you write), then document it. It will make your examiners job easier if they can see that you have already checked logically for deadlocks - all they will have to do is validate your assumptions.
    Regards, Andrew
    Raymond Tanner
    Greenhorn

    Joined: Jan 09, 2004
    Posts: 24
    Andrew, I cannot thank you enough!!!
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: NX: Data a singleton and no cache - trouble? Andrew help if you can