aspose file tools*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Locking Question 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 "Locking Question" Watch "Locking Question" New topic
Author

Locking Question

Alan Morgan
Ranch Hand

Joined: Apr 18, 2005
Posts: 113
Hi All,

Was reading a locking approach below from someone who got 80/80 and happy to see that it sounded like mine ( nice and simple )

Anyway one quote got my thinking:

Originally posted by Jesse Xie Y.S.:

5. Make sure that the process of checking if a record is locked by other thread or checking if the record is exist, before locked a record, should be keep in synchronized block.


Ok so in my Controller.book() I do:
Lock
Update
Unlock (in finally in case anything goes wrong)

In my Data.lock() I do:
Read to make sure it exists
Lock (in LockManager and synchronized)

In my Data.update() I do:
validateLock
then do the update

The steps in book(), lock() and update() are not synchronized.

My Controller is on the client side.
I’m thinking because Controller is on client side then it will only have one thread at a time so no synchronization needed.

I’m thinking possibly need a synchronize in lock() as between read of record to make sure it exists and call to LockManager.lock() thread could be swapped out.

And I’m thinking in update() I don’t need a synchronize cause the first check is validateLock so if it does not have access an Exception is thrown.

Any feedback on thought process above appreciated so I can forget about it for a while safe in the knowledge that I’m on the right track at least.

Thanks.
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11278
    
  59

Hi Alan,

Most of your post looks good. Just to clarify a few things though:

I’m thinking possibly need a synchronize in lock() as between read of record to make sure it exists and call to LockManager.lock() thread could be swapped out.
Yep. Alternatively you could lock the record regardless of whether it is a valid number or not, then afterwards confirm that it is valid and unlock the record if it is not valid. Personally I think your solution is going to be a little neater / more efficient.

And I’m thinking in update() I don’t need a synchronize cause the first check is validateLock so if it does not have access an Exception is thrown.
Well you don't need to synchronize the entire method, but you will need synchronization around the calls to the file access methods.

Regards, Andrew


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

Joined: Apr 18, 2005
Posts: 113
Originally posted by Andrew Monkhouse:
Well you don't need to synchronize the entire method, but you will need synchronization around the calls to the file access methods.



I was just looking at my Data class for another reason and I got to thinking about locking again.
And the line above from Andrew stuck in my mind.
So I looked at my class to see anywhere I access the Random Access File (RAF) and see if I synchronized access to it. So I made a list:

Synchronized
===========
update
create

Not Synchronized
================
read
delete
isValidRecord (checks if record has valid/invalid flag)



So lets take read(..) as an example.
It involves calls to seek, skipBytes and read.
If two threads were to call read() and the process went as follows:

Thread1 calls seek
Thread1 calls skipBytes
Thread1 swapped out
Thread2 calls seek
Thread1 calls read

Thread1 is now reading in the wrong position in the RAF.

If this is the case then all of the unsynchronzied methods mentioned above need to be synchronized. (or at least the blocks dealing with the RAF)

Am I reading this situation right ?
[ December 01, 2005: Message edited by: Alan Morgan ]
Conor O'Mahony
Greenhorn

Joined: Aug 08, 2005
Posts: 7
I synchronized all places where my Random Access File was accessed. Does this sound reasonable ?
Alan Morgan
Ranch Hand

Joined: Apr 18, 2005
Posts: 113
Originally posted by Conor O'Mahony:
I synchronized all places where my Random Access File was accessed. Does this sound reasonable ?



Conor,

Its starting to sound reasonable to me the more I think about it.
Just have to be careful of overkill.
I must go back and re-read the threading chapter of the certification book and see if it sheds any light.


Alan Morgan
Ranch Hand

Joined: Apr 18, 2005
Posts: 113
Just saw a mention of a timeout on a lock in another topic.

So instead of wait() call wait(time) to avoid deadlock.
My question is how long I should wait ?
The examples I have seen use 1000 but I'm not sure how to decide.
[ December 08, 2005: Message edited by: Alan Morgan ]
steve mcdonald
Ranch Hand

Joined: Nov 18, 2005
Posts: 46
Hi Alan,

> So instead of wait() call wait(time) to avoid deadlock.
> My question is how long I should wait ?
> The examples I have seen use 1000 but I'm not sure how to decide.

well there are 2 issues i think.

1. Transaction Max threshold - how long is too long ? for the current transaction to run. Actual processing time not including the wait on resource.

2. How long to wait for resource to be available and how and who is responsible to release resources that are held by abandoned clients.

The wait(time), will only address the issue of not waiting forlong if the resource is not available and let the user know that he/she cannot process because of ..... user friendly message. This will not address the core problem of releasing locked resources infinitely by abandoned clients.

On the other hand, this wait(time) call keeps consuming CPU intermittently, until the wait condition is satisfied, which i thought would not satisfy Sun's requirements "consuming no CPU cycles ". that's why i am not using the wait(time) call, though i coded initially and posted questions on this forum.

Having said that, implementing a mechanism of cleaning of unused/stale resources with a Transaction MAX Threshold and notifing waiting clients will provide solution to potential deadlocks.

Anyway, atleast this is my opinion.
Alan Mc Kernan
Ranch Hand

Joined: Oct 13, 2005
Posts: 59
Why do we need to look after "stale" resources?

Thats a pretty difficult problem - and i beleive its out of scope of the assignment (at least for URLyBird)
steve mcdonald
Ranch Hand

Joined: Nov 18, 2005
Posts: 46
> Thats a pretty difficult problem - and i beleive its out of scope
> of the assignment (at least for URLyBird)

Well I am doing the URLYBird also, the DBMain interface says to implement lock/unlock by this client.

// Locks a record so that it can only be updated or deleted by this client.
// If the specified record is already locked, the current thread gives up
// the CPU and consumes no CPU cycles until the record is unlocked.
public void lock(int recNo) throws RecordNotFoundException;

that means the client can call lock/unlock in any order, either in the business logic at the server or client. so if for some reason the client is exposed with this interface, then the business logic should protect from any other user from making changes while a record is locked.

in any case you can justify in your choices about your decisions.
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11278
    
  59

Hi Alan
So lets take read(..) as an example.
It involves calls to seek, skipBytes and read.
If two threads were to call read() and the process went as follows:

Thread1 calls seek
Thread1 calls skipBytes
Thread1 swapped out
Thread2 calls seek
Thread1 calls read

Thread1 is now reading in the wrong position in the RAF.

If this is the case then all of the unsynchronzied methods mentioned above need to be synchronized. (or at least the blocks dealing with the RAF)

Am I reading this situation right ?
Yep - you do need to synchronize either the method or the block around the {seek .. read}.

Taking that a step further though - what else is that method doing apart from the two method calls that you identified as having potential thread conflicts?

I think you might be validating the record number prior to the disk I/O. You might be checking whether the record read is deleted or not. And you might be converting from the bytes read into a String[]. You might be doing other things as well. Do any of these extra steps suffer from the same potential thread conflicts? If not, do they need to be inside a synchronized block?

So - in the argument between synchronizing a method, and synchronizing a block within that method - can you see which one I would lean towards?

Regards, Andrew
Andrew Monkhouse
author and jackaroo
Marshal Commander

Joined: Mar 28, 2003
Posts: 11278
    
  59

Hi Alan,
Just saw a mention of a timeout on a lock in another topic.
For the record - I believe that discussion of handling orphaned locks / locks held too long is outside of scope for the assignment.

Having said that though, I think it is something you would have to handle in real life, and it is easy enough to do, so discussion is good .

My personal view is that the instructions seem to indicate that I should be able to own a lock as long as I want. There is no indication of a timeout in the interface definition. There is no indication of a timeout anywhere else in the instructions.

So if you were to implement a timeout, you are introducing something that has not been asked for. Furthermore you will be specifying a time limit that other users may not be expecting, and (as your question indicates) there is no standard idea of what sort of timeout to put on it - in real life a decision on timeout values would either come about after discussion with the relevant parties (which we cant do) or be configurable (hmmm - we could end up with too many configurable options in our GUI if we are not careful).

So my personal opinion is that we should not be doing timeouts.

Given that, what are other options for handling orphaned locks:
  • Have the booking business method on the server so that there is no such thing as an orphaned lock (I also disagree with this, but it is an option).
  • If we are using Sockets, release any locks owned by a client when we receive the Exception from he socket we are listening on when the client disconnects.
  • For either RMI or Sockets, have a unique identifier for each connected client, and store that as the key for the locks in a WeakHashMap. When the client disconnects, the lock will be automagically removed from the WeakHashMap (I have oversimplified, but a search for WeakHashMap in this forum will provide more information).
  • For RMI, have a unique Remote class per connected client that implements Unreferenced. When the unreferenced() method is called, release any locks owned by the cient. (I have oversimplified, but a search for Unreferenced in this forum will provide more information).

  • Regards, Andrew

    PS - Sorry, very long day today, so I have not gone into any details. Feel free to ask questions though.
    [ December 09, 2005: Message edited by: Andrew Monkhouse ]
    steve mcdonald
    Ranch Hand

    Joined: Nov 18, 2005
    Posts: 46
    thanks Andrew, it made simple for the assignment. that's what i have been struggling to decide the scope in my assignment. In reality we need to handle different transaction isolations, locks such as shared locks, row level, table level and what not .... etc.

    well i just don't want to be hasty in making decisions. because i only have somuch patience and don't want to revisit this assignment over again.
    not that haven't enjoyed the process. I am already seasoned professional and just want to get through this one.

    Again thanks for your replies and i know it takes a great deal and effort to moderate.
    Alan Morgan
    Ranch Hand

    Joined: Apr 18, 2005
    Posts: 113
    Originally posted by Andrew Monkhouse:
    Hi Alan Yep - you do need to synchronize either the method or the block around the {seek .. read}.

    Taking that a step further though - what else is that method doing apart from the two method calls that you identified as having potential thread conflicts?

    I think you might be validating the record number prior to the disk I/O. You might be checking whether the record read is deleted or not. And you might be converting from the bytes read into a String[]. You might be doing other things as well. Do any of these extra steps suffer from the same potential thread conflicts? If not, do they need to be inside a synchronized block?

    So - in the argument between synchronizing a method, and synchronizing a block within that method - can you see which one I would lean towards?

    Regards, Andrew



    Hi Andrew,

    Thanks for the reply.

    Can I phone a friend for the answer to this one ?
    No I reckon you're leaning towards just synchronizing the block involving the actions on the RAF which makes sense to me.
    Alan Morgan
    Ranch Hand

    Joined: Apr 18, 2005
    Posts: 113
    Ok so I made my changes by introducing synchronized blocks in read(), delete() and isValidRecord().

    And then comes the re-run of my LockTest.
    Its basically a number of threads attempting to update record 1 with a name of Thread X (where x is the the threads number)
    When I used run it before with 20 threads I was never really sure what record 1 would end up being called.

    However now that I have made the code changes my record always ends up being called the name of the last thread.
    It seems they now get to update the record in the order that they are started. No matter whether I used 2, 20 or 2000 threads.
    This freaked me out a bit

    However when I think about it, it maybe makes sense.
    I mean now the threads have a lot more sychronization obstacles, so to speak, in their way before they reach the point when they can request a lock on the record.
    (By the way I can see Threads waiting for the lock on the record in lock() alright)

    So where they could race through read() and isValidRecord() before, now they have to wait if someone else got their first.
    So maybe this explains why they are lining up so obediently.

    Does my analysis make sense or am I after making a mistake somewhere ?

    Thanks.
    [ December 13, 2005: Message edited by: Alan Morgan ]
    Conor O'Mahony
    Greenhorn

    Joined: Aug 08, 2005
    Posts: 7
    I would also like to know if this is normal as I am having a similar situation.

    However I am synchronizing on methods rather than blocks.
    But I can see the point about inefficieny inherent in that and will look to change it.
    Alan Morgan
    Ranch Hand

    Joined: Apr 18, 2005
    Posts: 113
    Hey guys,

    Any one able to help out here ?
    I'm going home for Xmas and was hoping to get pretty much everything done
    but I'm worried about this issue.

    Thanks,
    Alan.
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11278
        
      59

    Hi Alan,

    Yes, this does make sense, especially since all your threads are running the same task.

    One thing you could do is to add some minimalist logging stating what the record is being updated with, save the output, then view the output later. You will possibly find that one or two threads (and sometimes even a block of them) may be called out of sequence, but in general you will find that towards the end of your run all the threads will be called in sequence.

    Regards, Andrew
    Alan Morgan
    Ranch Hand

    Joined: Apr 18, 2005
    Posts: 113
    As usual thanks very much for your input Andrew.
    I will do as you suggest but your comments do, at least, set my mind at ease.

    In case I'm not back on these boards before Xmas.....

    I wish you and yours a peaceful and happy Xmas and a prosperous New Year.

    Alan Morgan
    Ranch Hand

    Joined: Apr 18, 2005
    Posts: 113
    Hey all,

    As you can see from my comments made above I was just planning on synching the code that accesses the RandomAccessFile.
    However on further reflection I am starting to question this.

    Take for example my read() method on my Data class.

    <CODE>
    create byte array
    synhc on RAF
    {
    do stuff to read record into byte array
    }
    make sure that record not deleted
    if it is throw RecordNotFoundException
    Create the String array and fill it with info about record
    </CODE>

    So as you can see the RAF access is synched and so is safe enough.
    Next I check the record and see that it is not deleted
    Now thread 2 takes over the cpu and deletes the record just read.
    Thread 1 swaps back in and returns the record.
    However I have now just returned a deleted record thinking it was valid.

    So now I'm thinking synch the method as a whole or at least make the synch block much larger

    This issue also pops up in a similar way with methods such as update and valid record checks.

    Is my reasoning sound or am I missing something.

    Any help greatly appreciated as I really would like to sort out my locking once and for all as I hope to submit soon.

    Thanks
    Alan Morgan
    Ranch Hand

    Joined: Apr 18, 2005
    Posts: 113
    Originally posted by Andrew Monkhouse:
    Hi Alan Yep - you do need to synchronize either the method or the block around the {seek .. read}.

    Taking that a step further though - what else is that method doing apart from the two method calls that you identified as having potential thread conflicts?

    I think you might be validating the record number prior to the disk I/O. You might be checking whether the record read is deleted or not. And you might be converting from the bytes read into a String[]. You might be doing other things as well. Do any of these extra steps suffer from the same potential thread conflicts? If not, do they need to be inside a synchronized block?

    So - in the argument between synchronizing a method, and synchronizing a block within that method - can you see which one I would lean towards?

    Regards, Andrew



    OK I was just re-reading the post above from Andrew on this topic and then my reply to it.

    My reply and what I wrote in my latest post seem to contradict each other so maybe I picked Andrew up wrong.

    I thought originally that the extra steps were not in danger of going wrong in the presence of multiple threads but now I think they are.

    So checking if a record is valid and creating the String[] to return also need to be synched. This means that practically the whole method needs to be.

    Andrew - maybe you can come in on this one ?
    Andrew Monkhouse
    author and jackaroo
    Marshal Commander

    Joined: Mar 28, 2003
    Posts: 11278
        
      59

    Hi Alan,

    Lets assume for the moment that you do synchronize the entire method, and go through the same scenario as mentioned before: one client (thread) reading a record while another client (thread) is trying to delete it. Even with the entire method synchronized you are still left with the same potential race condition where the first client receives what it believes to be a deleted record when in fact the record is deleted.

    So, in my opinion, synchronizing the method is not going to gain you anything over synchronizing just a block.

    Did that help?

    Moving away from your question for the moment: The question might then become - do you want to ensure that clients only ever show the latest data? You could do this - you could have the server push any changes out to all connected clients. However this does not appear to be a requirement of the assignment (and therefore you cannot get any extra marks for implementing it); the network traffic generated by updating every client whenever there is any change could be troublesome if there were a lot of clients / a lot of changes; and it might be confusing to the client if records are changing / disapearing while they watch.

    Regards, Andrew
    Alan Morgan
    Ranch Hand

    Joined: Apr 18, 2005
    Posts: 113
    Hi Andrew,

    Your point is well made. Even if my full read operation is uniterruptable a second after I return the "valid" record to the UI it could become "invalid" by virtue of the next thread coming along and deleting it.

    So then I gain nothing by synching the whole method.
    In fact I'm back to the original mindset that synching just the access to my RandomAccessFile to ensure that I am reading/writing the correct place in my data file.

    And I reckon I'll just note the point about out of date UI data in my choices doc.

    Thanks again Andrew, at this rate I'll have to put a dedication to you in my documentation




    Alan.
     
    It is sorta covered in the JavaRanch Style Guide.
     
    subject: Locking Question
     
    Similar Threads
    Deadlock on the thin cleint
    Synchronization of public methods in DVDDatabase
    Hi, I have passed my assignment.
    Data Locking with a DB File.
    My Locking Approach