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

lock/unclock The correct question

Kalichar Rangantittu
Ranch Hand

Joined: Jan 15, 2002
Posts: 240
I have read many discussions here. My question is this. When a remote call is made to rmi object, will it always run on the same thread? The rmi specefication says may or may not. Now from what I have seen, if calls are made within a time out period say x, the thread will be the same. As far as our app goes, calls to read->modify->write which are part of the lock procedure should execute soon. If a client locks for 10 minutes then it should not be allowed to hold the lock for that long.
Question is really, will calls made within a reasonalble amount of time be guranteed to run on the same thread. I request people who have researched this topic to help me figure this out. Please dont tell me that you cannot do this as sun's rmi specefication says so.


Never be satisfied with anything less than the best and you will surely pass the test...
HenkGijsbert
Greenhorn

Joined: Jan 07, 2002
Posts: 28
Well, my experience is that within a reasonable amount of time it is handled by the same thread.
My FBN application runs as a train with this approach (See the 'Database Lock' thread started by Anurag Mishra).
regards,
Henk
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17257
    
    6

I never tested any of this, but When I read that you cannot guarantee the same thread will handle multiple calls from the client. I took it as why take the chance. I believe if you rely on the same thread, and code accordingly you will lose points.
It's like I know the fuse on this bomb is 10 seconds long, but my locking scheme will always be done before that, so it will defuse the bomb in time before it explodes.
I like that one.
Mark


Perfect World Programming, LLC - Two Laptop Bag - Tube Organizer
How to Ask Questions the Smart Way FAQ
Kalichar Rangantittu
Ranch Hand

Joined: Jan 15, 2002
Posts: 240
Mark, thanks for the info. Do you know of anyone who lost marks because they depended on getting the same thread? Please let me know so that I can make a design change.
amit ahuja
Ranch Hand

Joined: Nov 20, 2001
Posts: 38
You are right Mark, that multiple calls might not be on same thread. But as i see all the calls from client is atomic enough in our assignment. I mean we can safely treat every call to server from same same (or different) client independently.
in that sceniaro, i don't need to have any client ID (my thread ID is enough for that request processing).
Am i missing or wrongly interpreting?
amit
amit ahuja
Ranch Hand

Joined: Nov 20, 2001
Posts: 38
sorry Mark, i guess i know where i was wrong. I was just missing a simple flow.
Still ur input will be very valuable, on how to get a client ID?
which ever path i take to get clientID into picture forces me to change signature of lock() method. i do have LockManager a seperate class.
Please help.
amit
Kalichar Rangantittu
Ranch Hand

Joined: Jan 15, 2002
Posts: 240
Reposting here as:
I have some refernces which I would like to share in this matter:
1. From the sun site
"In all of these cases RMI may execute in separate threads. The JavaSoft reference implementation apparently has a single thread for all references from a single client VM but this should *not* be relied upon. "
2. From jguru
Technically, you already have a pool of threads. If your Server handles ten concurrent requests, then there are ten RMI Connection Threads processing these requests. As each request finishes, the RMI Connection Threads waits for the next request "n" seconds. If the next request comes in within this window, then a waiting RMI Connection Thread handles the request. Otherwise, the RMI Run Time destroys the RMI Connection Thread and must create a new RMI Connection Thread for the next request.
As far as we know the wait time, ( "n" seconds), is part of the RMI implementation and is not alterable by developers. During heavy usage the waiting pool should suffice.
From what I see above it is extremely rare that one gets the wrong thread, possible only if one sleeps for say 20 minutes and then reinvokes a remote method.
I hear that people have tested and found that they can make it happen more often, please let me know as to how you did it. Thanks, Kalichar
Gennady Shapiro
Ranch Hand

Joined: Sep 25, 2001
Posts: 196
We have discussed this topic a while back.
http://www.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=get_topic&f=25&t=001589
Shortly the answer is this: your requests will be handled by the same thread (which is confirmed by your testing, most likely) unless you do RMI over HTTP, then thread/object mappings aren't guaranteed. That is why RMI spec generalizes this by saying "not guaranteed".
Kalichar, what you are describing sounds like HTTP with KeepAlive option. By the way, RMI default timeout is 10 minutes (I am almost certain), and even though it can be reset I do not recall reading about thread pools in RMI spec, although it's a common topic in Web and App servers like Weblogic.
PS I did rely on the same thread to handle my requests in my assignment and I didn't lose any points on the Server part but did lose 3 point on the Genaral considerations, not sure if thats related to this.
[ January 15, 2002: Message edited by: Gennady Shapiro ]
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17257
    
    6

Amit. Try to do a search on this forum on Connection Factory, or client ID. Basically what I had was a ConnectionFactory class that had one method, getConnection. This was the class that was bound in my RMIRegistry. When a client did a lookup, it would get this instance, call getConnection, and the client would get it's own unique Connection Object, to use forever as it's own. This object implements the DataAccess interface. It also keeps track of it's own locks in a HashMap. THerefore unless the record number is in it's own HashMap, it can't call unlock.
Also my Data Class has a HashMap of all records all clients have locked, without any client ID. Because only cares that a record is locked.
You can have your LockManager handle the locks that I had in the Data Class, which along with added two methods to the Data Class is the reason I lost my 4 points, in the Server portion of my assignment.
Hope that helps.
Mark
Kalichar Rangantittu
Ranch Hand

Joined: Jan 15, 2002
Posts: 240
Thanks for the great answers all. I am left with the following dilemma:
a. If you change the signatures of the lock/unclock methods will I be penalized for it?
b. Thread based locking works fine using Sun's rmi/weblogic rmi. If tomorrow someone writes a new implementation that does not dedicate a thread to a client connection, my app will fail if I base it on that? Therefore may not be a good design choice afterall.
c. Has anyone implemented different signartures and not got penalized for it???
Kalichar Rangantittu
Ranch Hand

Joined: Jan 15, 2002
Posts: 240
Mark,
Thanks for the info. What are the two method that you added in your data class that cost you the 4 point? Is it because of new signatures for the lock/unlock?
Kalichar Rangantittu
Ranch Hand

Joined: Jan 15, 2002
Posts: 240
Gennady,
I sense from your explanation that you are not a proponent of the thread doing the locking. I was wondering how you explained your design choice for the same?
Thanks,
Kalichar
Roman Rytov
Ranch Hand

Joined: Jun 04, 2001
Posts: 75
I really don't understand the point of the discussion. What's the difference if calls are in the same or in other threads? I assign a unique ID during constracting the remote object and use it in Lock/unlock operation. No connection to threads.
Besides that I exported book(int rec, int seats) function so all lock/unlock are executed atomicaly.
May be I missed something? Please explain.


SCJA, SCJD, MCSD
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17257
    
    6

Kalichar

And

are the two method I added to the Data class. They are used for the criteriaFind method I added to the Data Class.
I think I could have created a sepeerate class to handle checking matching records from the data.
I had a CriteriaBuilder class which would take the data from my drop downs on the GUI, and change it to a comma delimited string, which got passed to the criteriaFind method, which called these two methods to put it into a HashMap, then to check record by record if the record matched the values in the HashMap.
If I had done it over again, I might have had the CriteriaBuilder be a helper class instead and take the values from the ComboBoxes, make the string, or directly to Hashmap, then pass the Hashmap to criteriaFind method in the Data class which would have been the looping through records and checking if it matches.
Something like that. I would have put more thought into it, and came up with something better. Even better than what I just wrote
Mark
amit ahuja
Ranch Hand

Joined: Nov 20, 2001
Posts: 38
Thanks Mark,
i remember ur advice of having seperate Lockmanager in some other mail-thread. and i have it. ;-)
Kalichar Rangantittu
Ranch Hand

Joined: Jan 15, 2002
Posts: 240
Mark,
Its kinda strange that they would penalize you for extra private methods. Anyway thanks for the info. Let me ask you one question, why did you create the connection object etc while connecting. Why couldnt the client manager simple have a static hash map of the locks he registed to?
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17257
    
    6

I couldn't have a hashmap of locks on the client side Because then the client has Database implementation knowledge. I wanted to completely seperate the client from the Database. And anything having to do with the locking scheme is a responsibility of the Data package, not the client.
The only interaction the client would have to get data is through the DataAccessFacade, which only had 6 public methods. getAirlines, getOriginAirports, getDepartureAirports, bookFlight, getAvailableSeats, and criteriaFind.
Mark
Gennady Shapiro
Ranch Hand

Joined: Sep 25, 2001
Posts: 196
Kalichar,
I am a big proponent of threads doing the locking. Except, evidently, you should not rely on a thread id while identifying the client. Instead you should rely on user's own server object reference -- that is always unique. I refer to ReadWriteLock design pattern here, most samples use thread id to uniquely identify a client -- this contradicts the RMI spec , even though it really works. I mistakenly relied on the same thread to identify the client but the examiner didn't mind much, I guess.

Now Roman, you say you use an id to uniquely identify users...how do you generate an id for a user? By his IP and port -- thats not realistic, not extendable, not safe, by generating a random number or timestamping - can you guarantee its uniqueness? by making a user login -- you could do that but FNB spec says not to and it's too much extra work.
[ January 16, 2002: Message edited by: Gennady Shapiro ]
Roman Rytov
Ranch Hand

Joined: Jun 04, 2001
Posts: 75
in my design there is no way to get such remote objects from the registry. Clients find one remote bound to the registry object and call its method getRemoteConnection() that call private constructor in wich I assigh long ID = timemils() + hashCode(). It's unique 100% all the time over the server.
Gennady Shapiro
Ranch Hand

Joined: Sep 25, 2001
Posts: 196
Originally posted by Roman Rytov:
in my design there is no way to get such remote objects from the registry. Clients find one remote bound to the registry object and call its method getRemoteConnection() that call private constructor in wich I assigh long ID = timemils() + hashCode(). It's unique 100% all the time over the server.

This is interesting. Your ID algorithm is incorrect for a few reasons:
1. According to Java API doc <I>It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results.</I>
2. The assumption that your hardware cannot produce 2 object within 1 millisecond time is invalid.
3. Now we know that the millies and the hash code maybe the same for two objects, therefore their sums may be the same.
4. Even if the hash and the millies are different there is a long shot of their sum stil being the same... like 3+7=10 and 4+6=10...you are actually hurting yourself by adding millies.

I agree that the chances of this happening are remote and your tests succeded 100% but mathematically it's unsound and no commercial system would accept this.
There are ways to generate a unique number (for example HTTPSession IDs are unique) but now we are going into authenticaion routines which is beyond the scope of this project, although nothing stops you from doing it.
My understanding of this project was that its goal was to use core technologies of J2SE such as Swing and RMI. If you create a unique server object for each client and let RMI handle uniqueness of each client you achieve precisely that. I can't be too far off on this since I got the perfect score for the server part.
Anyways, it's all up to you as long as you justify your choices.
Roman Rytov
Ranch Hand

Joined: Jun 04, 2001
Posts: 75
Thanks Genady for your reply. Since hashCode() for two different objects might be not the same you're right about inefficiency of my algorithm. I know from my practice that even three objects may be created in one millisecond (we had this bug in our system). I shouldn't have relied on hashCode() so much.
Another mistake I did in the description was instead of adding hashCode and millisec. actually I used shifting and logical adding. So the second error you pointed to couldn't happen. But anyhow, thanks. I changed my algorithm and now when my connectionFactory creates a new remote object it assigns unique ID by itself. So during life-time of the server all IDs are unique.
Gennady Shapiro
Ranch Hand

Joined: Sep 25, 2001
Posts: 196
Glad to be of help. But keep in mind that even shifts and bitwise logical operations may not guarantee uniqueness unless backed by math.
Kalichar Rangantittu
Ranch Hand

Joined: Jan 15, 2002
Posts: 240
The entire clue I beleive lies in the individual connection concept!!! Think about it.
Kalichar Rangantittu
Ranch Hand

Joined: Jan 15, 2002
Posts: 240
Mark didn't your connection object have a reference to the Data object? How could you make the Data object know about the locks unless it was independant of your Connection object?
Thanks
Forrest Xu
Greenhorn

Joined: Jan 30, 2002
Posts: 26
Hi,
how about If the client shutdown his machine but
locked a record on server side? this record seems
never been unlocked, unless server side can check
the client at a specific time to check if it is still alive.
does our assignment need to solve this problem?
can any one help me on it?
thanks,
java2de
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17257
    
    6

Kalichar
Mark didn't your connection object have a reference to the Data object?

Yes a reference.

How could you make the Data object know about the locks unless it was independant of your Connection object?

Well the connection object kept track of the locks that the one client had, once it was placed in the connection objects Hashset, it called the data classes lock method with the record number. So the Data class also had a Hashset of all locks by all clients.
In the connection object's unlock method, it first checked the connection objects' Hashset to make sure that client had it locked, before it would send it to the data class's unlock method.
In the connection object I also implemented the Unreference interface, and had code that would call the unlock method of the data class for each locked record the connection object had in it's Hashset.
Mark
Suchak Jani
Ranch Hand

Joined: Jan 24, 2002
Posts: 68
Mark,
When one has lock(int) and unlock(int), in the lockmanager utility class, then does one not also store all the locked record numbers in a collection type variable in the lockmanager ?
With the above being true what happens to :-
1. lock(int) and unlock(int) methods asked to be implemented in Data by the assignment instructions.
2. the lock all (-1) records function.
Do feel free to point me to some discussion thread if that's where you think the answer lies.
Thanks for all the help.
Regards
Suchak Jani
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17257
    
    6

Suchak Jani - I didn't realize this is where you had posted this question, so I had started a new thread on it
Mark
Kalichar Rangantittu
Ranch Hand

Joined: Jan 15, 2002
Posts: 240
I have a doubt. Lets say we have two connections to the database. One connection requests a lock(10) on a record. In the meanwhile another connection comes and locks the database with a lock(-1). Then lets assume that the first connection tries to do a modify, should that be permitted or not? I would think not
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17257
    
    6

Well it would be able to because the call to lock with the -1 has to wait until record #10 is unlocked by the other client.
Mark
Kalichar Rangantittu
Ranch Hand

Joined: Jan 15, 2002
Posts: 240
Thanks Mark..I thought you were gonna take a sabbatical . Anyway, the lock request for (-1) should not have to wait for all other locks to be released. Consider 3 clients who lock records and then die without clean up, does that mean one cannot get a lock(-1)? I would think not.
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17257
    
    6

I would think so.
I always state that the only "Client" that calls lock with -1 is when the server is shutting down, and it needs to close the data class. If it closes the data class while a client has a lock on it, KABOOM!.
So even though those 3 clients have the lock and are disconnected, the server should still wait till those records are unlocked. To Be Safe.
I was a Foxpro Programmer and I have seen it many times damn XBase dbfs!!!
Mark
In Hawaii(not Really) That's my kind of Sabbatical. Besides it's Saturday and I am at work because we have a release on Monday. And I loaded the Oracle Database last night, and this morning we(more they) are testing to make sure the data is good, and the program is good. I am just sitting here waiting for them to come in here with some sort of bug.
p.s The program is a VB 6 App I wrote.
Andrew Collins
Ranch Hand

Joined: Mar 28, 2002
Posts: 42
Originally posted by Mark Spritzler:
Kalichar

Well the connection object kept track of the locks that the one client had, once it was placed in the connection objects Hashset, it called the data classes lock method with the record number. So the Data class also had a Hashset of all locks by all clients.
In the connection object's unlock method, it first checked the connection objects' Hashset to make sure that client had it locked, before it would send it to the data class's unlock method.
In the connection object I also implemented the Unreference interface, and had code that would call the unlock method of the data class for each locked record the connection object had in it's Hashset.
Mark

Hi Mark,
I would appreciate your thoughts on this one :
I agree that using a LockManager here is a nicer, more OOP minded solution (as you previously stated :
Think of ways splitting responsabilities apart so that each class does one thing and only one thing
). This results in a LockManager that doesn't care who owns the lock, right ?! Isn't this poor reusability ? If I wanted to use this LockManager in another application I'd still have to duplicate the RemoteDataImpl's code that arranges the ownership of locks...
With this in mind, I don't know which option to prefer :
1.Leave things as they are, just state in the docs that you are aware of this "problem".
2.Move the responsability of checking who owns a lock to the LockManager
3.Provide the LockManager with code that checks who owns the lock, even though this has already been taken care of by RemoteDataImpl
I'm tending to prefer nr 3 but I'd like to hear your opinion on this one
Thanks
[ April 19, 2002: Message edited by: Andrew Collins ]
Sai Prasad
Ranch Hand

Joined: Feb 25, 2002
Posts: 560
Originally posted by Andrew Collins:
).
2.Move the responsability of checking who owns a lock to the LockManager
[ April 19, 2002: Message edited by: Andrew Collins ]

I would go with number 2 and don't do any checking in the RemoteDataImpl object. This is how I've implemented it. RemoteDataImpl delegates the lock/modify/unlock method calls to the LockManager object. This way it is reusable for future remote impl objects
Andrew Collins
Ranch Hand

Joined: Mar 28, 2002
Posts: 42
Hi Sai,
I can live with that
When I reconsider, I would do the same thing.
Nevertheless, I'm still wondering why Mark, deliberately I assume, has choosen to implement this logic spread over 2 classes instead of 1...
So Mark, if you're out there, please let me know
Regards,
A
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 17257
    
    6

I didn't have a LockManager. My locking code was in two places. first in the RemoteData class I have a hashset that tracks the locks that that one client has. I pass my actual calls to my Data class, which has it's own HashSet of all the locks, and it doesn't know what client has what.
In the RemoteData class, when you call unlock, it first checks it's own HashSet, if the record is in there, then it passes the unlock call to the Data class.
Using a LockManager, I would just pass the calls to it, rather than the Data class. That's all
Mark
Endre Moen
Greenhorn

Joined: Apr 25, 2002
Posts: 5
I am a big proponent of threads doing the locking. Except, evidently, you should not rely on a thread id while identifying the client. Instead you should rely on user's own server object reference -- that is always unique.

But what if two users on different computers have a reference to the server object at the same address? It is possible, just like the discussion about System.currentTimeMillis()+obj.hashCode(). So it is not 100% safe that either.


Sun-to-be Certified Java Developer
Chingiz Tairbekov
Greenhorn

Joined: May 01, 2002
Posts: 2
Imagine how it looks with GUI:
1. A very bad user A locks row 1
2. user A kills its client
3. A very good user B is trying to lock row 1 (book)
4. Client GUI for user B starts new thread for booking process to increase GUI responsivness
5. Now after couple seconds GUI tells to B that operation in progress.
6. User B should be able to cancel it
7. Now we have Connection object for user A with lock for row 1 and Connection object for user B in the wait state trying to get a lock for row 1
8. User B is trying to repeat booking and creates additional thread for Connection object for user B and so on...
Event if we provide Unreferenced implementation RMI waits 10 (be default) to get rid of Connection object.
The only way to avoid that problem I see in keeping a Set of Thread's for Connection object waiting for a lock and provide some kind of releasePendingLocks on Connection object interrupting own waiting threads.
In this case user can have control over loooong locking calls.
Sai Prasad
Ranch Hand

Joined: Feb 25, 2002
Posts: 560
Chingiz,
Here is my suggestion to avoid your scenario.
1) Do not instantiate a thread for every GUI call
2) Implement Unreferenced to take care of graceful exit by the client
3) Implement a custom cleanup thread on the server side to remove the unreferenced locks held by any client for any record in any table after a specific interval
Moreover the javadoc comment in Data class for the lock() method clearly says "This method blocks until the lock succeeds. No timeouts are defined for this." So if your custom cleanup thread wakes up every 5 seconds, you don't have to rely on Unreferenced() and wait for 15 minutes. In your example, user B will not be mad to wait for 5 seconds. I feel this is simpler than keeping track of threads and interrupting them.
Also during graceful exit, if you set your remote reference to null and call System.gc(), unreferenced() is called on the remote object instantly.
[ May 02, 2002: Message edited by: Sai Prasad ]
dean tomlinson
Ranch Hand

Joined: Jan 31, 2002
Posts: 94
hi mark,
didn't have a LockManager. My locking code was in two places. first in the RemoteData class I have a hashset that tracks the locks that that one client has. I pass my actual calls to my Data class, which has it's own HashSet of all the locks, and it doesn't know what client has what.
In the RemoteData class, when you call unlock, it first checks it's own HashSet, if the record is in there, then it passes the unlock call to the Data class.
Using a LockManager, I would just pass the calls to it, rather than the Data class. That's all


I am about to start work on the data server side of things and wondered if you be as so kind to review my understanding of the Database/Network Server.
The Database/Network Server is essentially the RMIConnectionFactroy that has been talked of? This internally holds a Data object and a lockmanager object that together provide the Database/Network Server functionality ? I have read that it is good to include the pattern name in any class that implements a pattern. But would it be better to call the ConnectionFactroy DataServer instead - to clarify it's role in the assignment.
I am planning to not modify Data at all in temrs of it's lock / unlock methods, becasue these are not required for local use. Thesefore these operations will be handled by the lockmanager.
your RemoteDataobject, is the remote object that implements the Data interface, and that is retrieved from the ConnectionFactory / DataServer's getConnnection method?
I am a bit confused becasue the requirments seem distinctly seperate the writing of the data server with the writing of the data client, yet with this connection factory, approach (which seems to be the way to satisfy all the requirements) kind of blurs the 2 together (as the data client performs much of the functionality of the data server, in the sense that the synchronisaion to the shared databse is handled by the clients and not centrally by the server - which doesn't do too much really other than act as a connection factroy ).
in terms of synchronising access to the shared Data object, and the shared hashset of locked records.
would you have synchronised blocks in each of these objects, that locked against "this" or would you lock at a level above in the RemoteData object, say on a shared object such as the Data object.
Any pointers, as always, greatly appreciated cheers, dean
[ May 02, 2002: Message edited by: dean tomlinson ]
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: lock/unclock The correct question