File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Two designs of locking mechanism 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 "Two designs of locking mechanism" Watch "Two designs of locking mechanism" New topic
Author

Two designs of locking mechanism

Ailsa Cape
Ranch Hand

Joined: Aug 10, 2005
Posts: 92
Hi, everyone.

Now I plan to design the Data class�s lock method. I have searched many posts here and found a lot of useful ideas. Here is my two designs which all have advantages and disadvantages, so I eager to receive your advices.
In the following designs, I decided to use a singleton class called LockManager to perform the actual locking work, and in the Data class�s lock method, it simply calls the LockManager�s lock method directly, and I use RMI in the server side.

The first design: synchronized the lock method.

The second design: synchronized the instance of HashMap.


In the first design, if there are four clients trying to update the same record No. 2 simultaneously, the first one might get the real lock. Then the second person will enter the lock method and be in the wait state if the first person hasn�t called the unlock method. What will the third person do? I think because the second person is still waiting and the lock method is synchronized itself, this person might not enter the lock method until the first one unlock it and the second one in turns locked it. But I am not sure the first one can run the unlock method when the second person is in the lock method since there is only one instance of LockManager class and at the same time only one thread can run in either lock or unlock method. If so, it will cause the second person waiting for ever.

In the second design, it can make all clients who update the same record simultaneously waiting in the synchronized block, thus avoid blocking them out of the lock method. But it has to deal with �orphan� client and I think if a user in the process of locking a record, any other persons can�t unlock their locks at the same time even though they own the exact keys to those locks because the lockedRecords object has been synchronized and they have to wait the locking process finished. Is it right?

I don't quite get at the method isLocked. Where is the proper place in the client side to call the Data.isLocked()? Even though a user calls it and receives the false value, it might implicitly be changed by other client after that, so the user can't lock this record at all.

Any advice will be appreciated!
Ailsa Cape
[ September 06, 2005: Message edited by: Ailsa Cape ]
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11432
    
  85

Hi Ailsa,

Lets try these out with three clients all trying to lock the same record simultaneously. For the following, assume BLOCKED means Thread.State.BLOCKED and WAITING means Thread.State.WAITING. I am also going to assume that notify() is called in the unlock method:

Case one:
  • Client A obtain mutex on instance of LockManager and enters lock method
  • Client B tries to enter lock method - BLOCKED trying to obtain mutex on instance of LockManager
  • Client C tries to enter lock method - BLOCKED trying to obtain mutex on instance of LockManager
  • Client A locks desired record
  • Client A leaves synchronized method, releasing mutex on instance of LockManager.


  • JVM picks one of the BLOCKED threads and runs it:
  • Client B obtain mutex on instance of LockManager and enters lock method
  • Client C still BLOCKED trying to obtain mutex on instance of LockManager
  • Client B determines that desired record is locked, enters WAITING state, releasing mutex on instance of LockManager.


  • JVM picks one of the BLOCKED threads and runs it:
  • Client C obtain mutex on instance of LockManager and enters lock method
  • Client C determines that desired record is locked, enters WAITING state, releasing mutex on instance of LockManager.


  • We will come back to this point in our discussions later!
    Now client A wants to unlock the record:
  • Client A obtain mutex on instance of LockManager and enters unlock method
  • Client A releases desired lock
  • Client A calls unlock to wake up either client B or C - but we don't know which
  • Either client B or C transitions from WAITING state to RUNNABLE state (very temporary).
  • Either client B or C transitions to BLOCKED state trying to obtain mutex on instance of LockManager.
  • Client A leaves unlock method, releasing mutex on instance of LockManager.

  • Phew!

    Note that at the point where I said "We will come back to this point", client A owns the lock, clients B and C are in WAITING state, and nobody owns the common mutex.

    Ok, lets try it again with case two:
  • Client A enters lock method, and obtains mutex on instance of lockedRecords and enters synchronized block
  • Client B enters locked method, tries to enter synchronized block - BLOCKED trying to obtain mutex on instance of lockedRecords
  • Client C enters locked method, tries to enter synchronized block - BLOCKED trying to obtain mutex on instance of lockedRecords
  • Client A locks desired record
  • Client A leaves synchronized block, releasing mutex on instance of lockedRecords.


  • JVM picks one of the BLOCKED threads and runs it:
  • Client B obtain mutex on instance of lockedRecords and enters synchronized block
  • Client C still BLOCKED trying to obtain mutex on instance of lockedRecords
  • Client B determines that desired record is locked, enters WAITING state, releasing mutex on instance of lockedRecords.


  • JVM picks one of the BLOCKED threads and runs it:
  • Client C obtain mutex on instance of lockedRecords and enters synchronized block
  • Client C determines that desired record is locked, enters WAITING state, releasing mutex on instance of lockedRecords.


  • We will come back to this point in our discussions later!
    Now client A wants to unlock the record:
  • Client A enters unlock method, obtains mutex on instance of lockedRecords, and enters synchronized block
  • Client A releases desired lock
  • Client A calls unlock to wake up either client B or C - but we don't know which
  • Either client B or C transitions from WAITING state to RUNNABLE state (very temporary).
  • Either client B or C transitions to BLOCKED state trying to obtain mutex on instance of lockedRecords.
  • Client A leaves synchronized block, releasing mutex on instance of lockedMethods.



  • Note that in the second case I did not show client A leaving the lock or unlock methods - it is immaterial since we are only interested in the synchronized blocks.

    Note that at the point in the second case where I said "We will come back to this point", client A owns the lock, clients B and C are in WAITING state, and nobody owns the common mutex.

    So for both cases one and two, at the point just before client A tries to unlock the record, clients B and C are in WAITING state, and nobody owns the common mutex. So for all intents and purposes, these are working the same way.

    I haven't even discussed orphaned locks, as they don't have any bearing on the discussion above. We need to be certain that we are in agreement that the two options are functionally equivalent before we go further. Then in a seperate discussion we can discuss orphaned locks as they relate to either solution, since the same issues will apply to the functionally equivalent solutions.

    Likewise I haven't discussed the isLocked question.

    Regards, Andrew


    The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
    Ailsa Cape
    Ranch Hand

    Joined: Aug 10, 2005
    Posts: 92
    Hi, Andrew

    Thanks a million!
    With your great help, I have gained a clear picture of the working manner of wait and notify methods and the states of BLOCKED and WAITING. I realize the mistake I made. It is true that the two designs are identical in function.

    Now, I fully understand your previous post about How to consume no CPU cycles. In the great post, you mentioned a case about temporary thread starvation. In this situation, although simply using notify method from within the unlock() can work, it might cause lower efficiency. So if I hope to get high marks in the locking section , do you think I should have to implement a notify system like Peter�s to inform the proper thread in the waiting sequence in which all threads are trying to lock the same record?

    I think my final solution of business logic should be described as following.
    I have to introduce the base backgroud of my solution.
    1)I use the Data class as a Facade to the DataAccess and LockManager classes. These classes both use singleton design pattern, so there is only one instance of DataAccess/LockManager class.
    2)I also use cache to store the db records.
    3)In order to have thread safe access to the db file, I have to apply synchronized modifier to the DataAccess class�s update method.
    4)In the client software, I called the sequence �Data.lock()-Data.read()-Data.update()-Data.unlock()�.
    Assume there are only three clients who update the db file at the same time. Client A updates record 1, client B also updates 1 and client C updates record 3. They might act in the following way.

    If so, I think there is only one specific record in the database file which can be really updated by only one client at any given time. Does it reduce concurrent access to my database file or is it just the right way to do so?

    And I still can�t find a right place in the client software to call the Data.isLocked(), could you please give me a hint about when and where we need this method?

    Thanks in advance!
    Regards, Ailsa Cape
    [ September 07, 2005: Message edited by: Ailsa Cape ]
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11432
        
      85

    Hi Ailsa
    So if I hope to get high marks in the locking section , do you think I should have to implement a notify system like Peter’s to inform the proper thread in the waiting sequence in which all threads are trying to lock the same record?
    What I think is immaterial

    What you need to do is make your own mind up about these things. You have to write your design decisions document, and you have to sit for the written exam. You cannot really write a design decision as "Andrew thinks this is good" . You have to be able to make arguments that you believe.

    For what it is worth, I (and most of the other bartenders who have worked in this forum or who have been involved in the certification process at Sun) believe that the simplest design is probably the best. As Sun says: "You will not receive extra credit points for work beyond the requirements of the specification.". So you cannot get extra marks for developing a queueing system like Peters. However, if you want to develop such a solution just as part of your learning exercise then I am more than willing to discuss it.

    If so, I think there is only one specific record in the database file which can be really updated by only one client at any given time. Does it reduce concurrent access to my database file or is it just the right way to do so?
    Well there is only one physical flat file residing on a single disk, so there can only ever be one record being physically updated at any given time - a far more advanced database (such as Oracle) might be able to improve that by putting different tables on different slices which may map to different partitions .... but this is all far too advanced for SCJD.

    What you need to do is to accept that at some point you cannot have concurrent operations, but to try and minimize the cases where one operation is blocking another.

    And I still can’t find a right place in the client software to call the Data.isLocked(), could you please give me a hint about when and where we need this method?
    Maybe you don't need it . Not all versions of the assignment have this method, so it is certainly possible to create a solution without it.

    If your lock ... read ... validate ... update ... lock cycle took a long time to process, you could check whether the record is locked before attempting to gain your own lock, and if so ask the user whether they wish to try to book the record. Personally I don't see much value in this.

    You might also use this at the point where you are shutting down the database. But again, I think there are easier ways of handling a shutdown.

    Regards, Andrew
    Ailsa Cape
    Ranch Hand

    Joined: Aug 10, 2005
    Posts: 92
    Hi, Andrew

    Thank you very much!
    I believe what Andrew thinks is good is really excellent, but I will keep it in mind and avoid using it as an argument in my design decision.

    I might as well comply with Sun's requirements which you have pointed out, but I am all ears to learn how to develope a queueing system. It is interesting.

    Thank you for confirming my design of the business logic. Now I understand the design is not perfect though, it is really proper for the requirments. I never use Oracle before, with your introduction I realize it is a powerful database system.

    What you need to do is to accept that at some point you cannot have concurrent operations, but to try and minimize the cases where one operation is blocking another.

    Do you mean I should pay close attention to "dead" and "orphaned" locks? Now I think if I can't deal with the "orphaned" locks properly, I would cause some specific locks existing for ever. I'll try to use Unreferenced interface to do it, but in which cases the dead locks would occur I have no idea.

    Although I also think calling Data.isLocked() is redundant in the client software, my requirments do want me to implement this method, so
    I think the places you mentioned to call Data.isLocked() are reasonale.

    Thanks in advance!
    Regards, Ailsa Cape
    wu qiang
    Greenhorn

    Joined: Sep 07, 2005
    Posts: 5
    Hi Ailsa
    About the dead lock I deal with it using a timer.


    if a client lock a record over 30 sec ,the server will treat it as a dead client ,then server will automatically relaease the lock.

    if client A is not a dead but very slow, unlock record 1 will throw a security Exception after 30sec.

    what do you think about this.
    regards
    Jan Groth
    Ranch Hand

    Joined: Feb 03, 2004
    Posts: 456
    hi,

    i'm not alisa, but anyhow... ;-)

    that's a quote from myself from another thread:


    starting my application, i thought about the same question as you. i decided to implement a WatchDog thread, which kills lock on a time-out base.

    but there are a number of problems going with it:

    - you need to find a reasonable standard configuration

    - you need to provide a reasonable configuration possibility for the watchdog
    (but also avoid the need for sun to manipulate any files by hand)

    - killing a lock will lead to a whole bunch of new cases:

    - say the lock-issueing thread (T) is not dead, just very very slow. what if you kill the lock in exactly the same moment when T writes to the database? or has just written to the db, simply not releasing the lock? another thread will immediatly aquire the lock and try to write himself... not good.


    i'm almost finished with my application, but i'm short before replacing the watchdog witch something more stable in terms of db-consistency.

    i'm very interested in any other opinions on this subject... Please share your thought with me.


    and the newest update: i decided to delete it. way too much complexity in my eyes...;-)

    many greetings,
    jan
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11432
        
      85

    Hi Ailsa,

    Originally posted by Ailsa Cape:
    If so, I think there is only one specific record in the database file which can be really updated by only one client at any given time. Does it reduce concurrent access to my database file or is it just the right way to do so?

    Originally posted by Andrew Monkhouse:
    What you need to do is to accept that at some point you cannot have concurrent operations, but to try and minimize the cases where one operation is blocking another.

    Originally posted by Ailsa Cape:
    Do you mean I should pay close attention to "dead" and "orphaned" locks?
    Nope. My comment has nothing to do with dead or orphaned locks.

    I was responding to your comment about "I think there is only one specific record in the database file which can be really updated by only one client at any given time." You seemed to be concerned about this, so I was just commenting that trying to allow multiple concurrent modifications to a single file was not possible. However it is only really physical file access that reduces concurrency - any other operation could potentially be optimised to provide maximum concurrency (or to give the opposite, worst case, scenario, make all your remote methods synchronized, and have zero concurrency on the server :roll: )

    Originally posted by Ailsa Cape:
    Now I think if I can't deal with the "orphaned" locks properly, I would cause some specific locks existing for ever. I'll try to use Unreferenced interface to do it,


    OK. Again, this is something that is not required by the instructions, but it is a fun subject, so feel free to discuss it - you will almost certainly get plenty of opinions on it.

    Originally posted by Ailsa Cape:
    but in which cases the dead locks would occur I have no idea.
    At present deadlocks probably cannot exist in your client application. But what happens if somebody later changes your client - what happens if the client application tries to lock two records simultaneously? Could deadlock potentially occur?

    Regards, Andrew
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11432
        
      85

    Hi Wu & Jan,

    I agree with Jan's comments about the problems with a timer. Plus I have problem with whether a timer is allowed when you consider the documentation provided for the lock method - my reading of the documentation does not allow much room for a timer.

    I much prefer Ailsa's current way of handling dead clients: using the Unreferenced interface (RMI), or catching the Exception thrown when a Socket is closed, or using a WeakHashMap for either RMI or Sockets.

    But
  • As I mentioned to Ailsa, I think that these are not requirements of the assignment.
  • I think that this is actually outside the topic in hand - namely the locking mechanism. These should really be discussed in a separate thread as they are part of your server solution.


  • Regards, Andrew
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Two designs of locking mechanism