aspose file tools*
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes B&S: OK to assume lock(), update(), unlock() called from same thread? 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 "B&S: OK to assume lock(), update(), unlock() called from same thread?" Watch "B&S: OK to assume lock(), update(), unlock() called from same thread?" New topic
Author

B&S: OK to assume lock(), update(), unlock() called from same thread?

Michal Charemza
Ranch Hand

Joined: Jul 13, 2004
Posts: 86
Hi all,

I am using RMI, and a thin client, so lock(), update(), unlock() are called from a single method in a wrapper class, DBAdapter, in one RMI call, and so in the same thread. I only have one instance of DBAdapter and Data (the class that implements DBMain, which specifies lock(), update(), and unlock()).

Is it ok to design my Data class that assumes that lock(), update(), and unlock() are all called from the same thread? This is to use the Thread.currentThread() to try to adhere to the spec for lock():

"locks a record so that if can only be updated or deleted by this client".

In my thinking I take "this client" to be the physical client across the network.

However, this behavior is only guaranteed because of the way I implement the calling class. Some possible future class could call lock() on behalf of one client, and then call "update()" on behalf of another, but all in the same thread (this could happen with multiple RMI calls), and so the second would illegally be able to update the record.

At the moment I am leaning towards keeping my assumpion, and specifing in the API for Data that any class must call lock(), update(), unlock() from the same thread. Is this OK?

Michal
Michal Charemza
Ranch Hand

Joined: Jul 13, 2004
Posts: 86
Originally posted by Michal Charemza:

However, this behavior is only guaranteed because of the way I implement the calling class. Some possible future class could call lock() on behalf of one client, and then call "update()" on behalf of another, but all in the same thread (this could happen with multiple RMI calls), and so the second would illegally be able to update the record.

Also, the obvious (and often mentioned in the forums) problem that if lock() and update() are from different RMI calls, they could in different threads and so the client wouldn't be able to update the record it should. (however as explained above my implementation of the calling class forbids this - but I don't know if I can assume in my design of Data that the calling class forbids it )

Michal
[ June 02, 2005: Message edited by: Michal Charemza ]
John Smith
Ranch Hand

Joined: Oct 08, 2001
Posts: 2937
Also, the obvious (and often mentioned in the forums) problem that if lock() and update() are from different RMI calls, they could in different threads and so the client wouldn't be able to update the record it should. (however as explained above my implementation of the calling class forbids this

By which means does your class "forbid" the invocation of lock(), update(), and unlock() in more than one thread? From what I remember in my instructions, it is the client that must make those calls, and I just don't see how you can force RMI to use a single thread for those remote calls.
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Michal:

I believe you are thinking too hard (admirable by the way, as long as it does not lead to an overcomplicated solution)!

In your particular scenario, I don't think there is any way you can uniquely identify the client between invocations with no "common" context or a way to have any persistent information between logical client sessions (this is all assuming a "thick client" situation with the client directly accessing the data object).

As you noted, since your lock-update/delete-unlock sequence is wrapped within a single RMI invocation, you are guaranteed that the situation would not occur for you (unless of course the server crashes in which case all locks are lost anyway). As far as I can see, I think this is the best you can do under the circumstances.

I would be happy with documenting the limitation in choices.txt and move on to bigger and better things, given the interface you were supplied.

Reza


Independent Consultant — Author, EJB 3 in Action — Expert Group Member, Java EE 6 and EJB 3.1
Michal Charemza
Ranch Hand

Joined: Jul 13, 2004
Posts: 86
John Smith:

I thought I posted a reply to your post yesterday, but obviously I didn't so here it is:

In my instructions, it doesn't say that the client must make those calls (for which I am pleased, I really really don't like the idea of the client having that much control, but from this forum I realise this is debatable...).

The reason that my design forbids the invocation lock(), update() unlock() in more than one thread is that the Data class (that implements DBMain that defines the lock(), update(), unlock() is not visible to the client. Only my wrapper class DBAdapter, which has a "book()" method that makes the calls. Since a single RMI invocation will call book(), the call the lock(), update(), unlock() will all happen in the same thread.

(Obviously?) for a later call to book(), it could use the same thread - but this wouldn't matter in my design.


Reza:

Thank you for your advice. I will wrap the Data class as described, and document my choice.

Phew! That's one descision made...

Michal.
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Michal:

Just out of curiousity, you will still be doing the Thread.currentThread().setName()/getName() trick to check that the exact client that requested lock is doing the unlock, right? Remember, the opposite situation, that is, more than one client using the same RMI thread is very common in your scenario. Just making sure.

Reza

P.S.:
* Two clients using the same RMI thread instance will still not break your "DataAdapter" class because the lock() invocation takes care of concurrency if Data is a singleton.

* I am sure I don't need to tell you this, but just making sure. Don't let dealing with online forums bother you or push you into desicions you didn't fully think through. That's just the nature of the beast. Just be patient...there are a lot of good people and good ideas on this forum...
[ June 04, 2005: Message edited by: Reza Rahman ]
Michal Charemza
Ranch Hand

Joined: Jul 13, 2004
Posts: 86
Originally posted by Reza Rahman:
Just out of curiousity, you will still be doing the Thread.currentThread().setName()/getName() trick to check that the exact client that requested lock is doing the unlock, right? Remember, the opposite situation, that is, more than one client using the same RMI thread is very common in your scenario. Just making sure.

I wasn't going to use that trick. Since originally posting I've been reading up on java.util.concurrent.locks , and I think I will use ReentrantLock that just depends on the Thread itself (I believe), and doesn't change its name. ReentrantLock is (I hope I've got my vocab right!) a mutex (mutual exclusion) lock that allows one thread to have a lock at a time. As far as I understand it, you can set this to be "fair", i.e. it will implement a lock queue.

(Actually I think I will use some sort of collection of ReentrantLocks... one for each record)

Do you (or anyone else) think this is a bad idea? I'm not sure by how your "opposite situation" above means that I should use the rename trick.

Thanks,

Michal.
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Michal:

As far as I know, in the scope of this project, ReentrantLock won't get you anything more than what you are already getting with the synchronized keyword (feel free to tell me I am wrong, I haven't really used java.util.concurrent on a real project and my knowledge is shallow in that area).

First and foremost, the way you were planning to do things will accomplish the goal of only letting one client doing the lock-unlock sequence. Let me repeat: you are just fine there.

Using the thread naming trick would accomplish two goals:

1. It would force any client using your data class directly to also use a single thread to call lock and unlock, just as you are. You could document this fact as a part of how the API you designed is suposed to work. This will not violate any requirement.

2. It will also act as a final fail-safe for you code. Please don't ask how your code might break -- let me pose a hypothetical:

Suppose that there is a bug in your code that blocks the first
invocation and lets the second client go through without obtaining
the lock instead of vice-versa (outlandish, I know). The second
client will now unlock sucessfully because you
did not uniquely identify the lock as long as RMI is using the same
thread pool for the second request. The poor first lock will finally
do it's thing and find that there is no lock to unlock!

Setting the thread name to something unique when the lock is obtained and checking for it in the unlock method will surface this bug properly.

Hopefully, this will give you enough food for though. Let me be clear, don't implement this if you deem it to be overkill - it is a lot of additional headache to deal with something that probably won't happen with your code anyway. Hope this helps.

Best,
Reza
Michal Charemza
Ranch Hand

Joined: Jul 13, 2004
Posts: 86
Originally posted by Reza Rahman:

As far as I know, in the scope of this project, ReentrantLock won't get you anything more than what you are already getting with the synchronized keyword (feel free to tell me I am wrong, I haven't really used java.util.concurrent on a real project and my knowledge is shallow in that area).

I think that if using it in "fair" mode it will implement a lock queue (this is how I read the API) - althugh I am undecided whether to use it.
Originally posted by Reza Rahman:

2. It will also act as a final fail-safe for you code. Please don't ask how your code might break -- let me pose a hypothetical:

Suppose that there is a bug in your code that blocks the first
invocation and lets the second client go through without obtaining
the lock instead of vice-versa (outlandish, I know). The second
client will now unlock sucessfully because you
did not uniquely identify the lock as long as RMI is using the same
thread pool for the second request. The poor first lock will finally
do it's thing and find that there is no lock to unlock!

Setting the thread name to something unique when the lock is obtained and checking for it in the unlock method will surface this bug properly.

I am a bit confused by your wording. I think that you mean this (correct me if I'm wrong):

1. Client A: Locks the record
2. Client B: Manages to update record without getting the lock
3. Client B: Unlocks the record
4. Client A: Updates the record
5. Client A: Tries to unlock the record - but its not locked!

If this is the senario, then my design would not allow this to happen (as far as I can tell) (this is using a ReentrantLock object for each record):

At step 2: In my update() method, I would check if the current thread has the lock.
In ReentrantLock there is the isHeldByCurrentThread() method to do this. If it's not held I would throw some sort of exception. (probably runtime, as if this is the case something has gone seriously wrong).

At step 3 (if manages to get here): In unlock(), ReentrantLock.unlock() would throw an IllegalMonitorStateException if the current thread doesn't have the lock.

I am also slighlty confused at your usage of "RMI thread pool", and how this relates to the problem. If two threads are running concurrently, then they must be using different threads (and have corresponding different Thread objects - and I think the ReentrantLock uses the current Thread object (i.e. Thread.currentThread()) as the "owner" of a lock).

Do you agree that my design will not let (my interpretation of) your bug to happen (at least not without throwing an exception? (of course if I've misunderstood I would very much like you to explain it again!).

Thanks,

Michal
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Michal:

I apologize for my choice of terms. I have been told about this problem I have before and the need to be vague for the certification isn't helping matters any... . Nevertheless, I will try my best:

Your understanding I believe is absolutely correct; more than likely the same instance from the RMI thread pool (or instances with the same name) won't be running this close to each other. However, remember that you realy can't make very many assumptions about how RMI thread pooling is handled. The native Windows 98 threading partment model, for example, causes some very strange behaviour.

All in all, I do believe your approach is just fine in terms of the handling the particular bug I cooked up on the fly.

The point I am trying to make is that you still could implement the thread naming trick to avoid the following (extremely far fetched and highly artificial) scenario:

1. Thick clients are using your data class directly.
2. they use separate invocations for lock, update and unlock (remember, you won't be able to predict which RMI thread pool will handle which request).
3. Thick client A locks record 1 using pooled thread C.
4. Thick client B makes a request to lock record 1 after the previous method call returns. Out of sheer dumb luck, this request gets assigned pooled thread C as well (which technically is still the holder of the ReentrantLock, causing the Reentrant.lock method to succeed again).
5. Thick client B updates the record.
6. Think client B unlocks the record.
6. When poor "good" thick client A comes back and hopefully gets assigned the same pooled thead, it will still fail.

Another variation of this problem is that clint B above plain old never uses lock/unlock but still succeeds becuase it happens to be assigned the same pooled thread.

Thread name assigning/checking will stop this from happenning. In addition, it will give you three additional benefits:

1. Effectively disable the thick client issue, since you will have defeated the problems caused by thread pooling.
2. Client's unlockign records they don't own.
3. Better expose any other unforeseen issues you might have even in the thin client scenario.

Hope this helps.

Reza
[ June 04, 2005: Message edited by: Reza Rahman ]
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Michal:

I took a second (and longer) look at the ReentrantLock object. I see that it has a getHoldCount() method to deal with precisely the scenario of calling lock() method twice from the same thread (possibly different clients in RMI).

I still cannot think of a way of dealing with errant clients using the same thread and calling unlock without calling lock first.

Reza
Michal Charemza
Ranch Hand

Joined: Jul 13, 2004
Posts: 86
Originally posted by Reza Rahman:
Thread name assigning/checking will stop this from happenning. In addition, it will give you three additional benefits:
1. Effectively disable the thick client issue, since you will have defeated the problems caused by thread pooling.

I'm assuming by "diasable the thick client issue" you mean that "there is no problem with thick clients using the Data class directly". If so, I think I disagree with you (at least for my specs).

In my specs it states that lock() "locks a record so that it can only be updated or deleted by this client". I take this to mean that a check must be made in update() to make sure that the lock is held by this client. If using a thick client, and the thread naming trick, the call to update() could be in a different thread that called lock(), and so would be in a different thread. Thus update() would fail (i.e. throw an exception) when it shouldn't. This would be the same if the thread re-naming trick was used, or my case.

What do you think?

Originally posted by Reza Rahman:
[QB]2. Client's unlocking records they don't own.

Can you give any examples of where the nameing trick would be different to my method of just using the Thread object? I can't think of any.

Michal.
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Michal:

As posted above, the only loophole that Reentrant lock might be subjected to that thread renaming would not is the reusing of the pooled thread that you (or anyone else) would not be able to control.

You are absolutely right though, either method aims to disable the calling of the lock, update and unlock methods from different threads.

Let me repeat what I said earlier though, I wonder if this case I am contructing is obscure enough to not matter. Remember, my view point is biased by the "lock cookie" based interface I have. I honestly think the Reentrant locking method you are describing is a very good way to implement the interface you were given.

Great debate by the way...

Reza
Charlie Goth
Ranch Hand

Joined: Feb 26, 2004
Posts: 60
Originally posted by Michal Charemza:

Is it ok to design my Data class that assumes that lock(), update(), and unlock() are all called from the same thread? This is to use the Thread.currentThread() to try to adhere to the spec for lock():


I'm no expert but I'm assuming the examiner will run some sort automated program to rigourously test our code. In those circumstances that assumption will be invalid, meaning the examiner will have to use his brain to figure out if your code will work properly. I wouldn't think they'd fail you for it but I'm not sure they'd like you for it either.


SCJP (77%)
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Charlie:

Actually, no automated tests are run against the code (not any more at least). In either case, there simply is no other option but to limit the relevant data class methods to be called from a single thread. Do you have an idea that would suggest otherwise?

Thanks for sharing your thoughts...

Reza
Charlie Goth
Ranch Hand

Joined: Feb 26, 2004
Posts: 60
*stands corrected*

I haven't read the whole thread, but are you trying to ensure that the same client calls lock(), update(), unlock()? Is that necessary? Can't just rely on the client having the correct cookie to update and unlock?
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Charlie:

Give the entire thread a closer look. He is one of the poor souls who do not have the lock cookie mechanism you and I do.

Reza
John Smith
Ranch Hand

Joined: Oct 08, 2001
Posts: 2937
MC: Since a single RMI invocation will call book(), the call the lock(), update(), unlock() will all happen in the same thread.

Here is the story. When the next client calls book(), the execution may happen in the same RMI thread (the one used to execute book() for the first client). That is, RMI may choose to reuse the previous thread. A very tragic thing will happen -- the identities of two different clients will be mixed.

Here is what I suggest -- drop that RMI thread identity approach and think of something more natural. For example, if each client requested a connection object from the server, that object itself would uniquely identify the client.
[ June 04, 2005: Message edited by: John Smith ]
Michal Charemza
Ranch Hand

Joined: Jul 13, 2004
Posts: 86
Originally posted by John Smith:
MC: Since a single RMI invocation will call book(), the call the lock(), update(), unlock() will all happen in the same thread.

Here is the story. When the next client calls book(), the execution may happen in the same RMI thread (the one used to execute book() for the first client). That is, RMI may choose to reuse the previous thread. A very tragic thing will happen -- the identities of two different clients will be mixed.

At the moment in my design, as you say, there is no way (at the moment) to uniquely identify the client between calls (eg by using the connection object like you suggest). I don't think this matters. Nothing would go wrong if the same thread was used (as far as I can tell)

The server doesn't care where a request came from. In future versions this may be necessary for some reason, but think it would be overcomplicting the solution. I think I would docuemtent this choice.

Anyway, this couldn't happen in the Data class - this is the class that implements lock(), update(), unlock(). I do not have any "cookie" parameters specified, like others do. I could not use the connection objects in this class - so I am back to whether I can design Data to assume that lock(), update() and unlock() are called from the same thread. From all the discussion, I think that I must do - I have no alternative (whether I use the naming ID trick or not).

Michal.

(NB I know I've been saying lock(), update(), unlock(), but I do actually mean lock(), read(), update(), unlock() (to check that the record hasn't changed... which is the whole point of locking)
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Michal:

I was curious from our discussion and did a bit more in-depth research on RMI thread handling. You are absolutely right, there cannot be two concurrent threads running with the same thread "identity" invoking remote methods.

The specified RMI behaviour is that an unused thread from the thread pool, meaning one that is not either running or waiting is assigned an incoming remote method invocation request.

Reza
Michal Charemza
Ranch Hand

Joined: Jul 13, 2004
Posts: 86
Originally posted by Reza Rahman:
I was curious from our discussion and did a bit more in-depth research on RMI thread handling. You are absolutely right, there cannot be two concurrent threads running with the same thread "identity" invoking remote methods.

Yes! This is indeed exactly how I think it works. Thus (just for absolute clarity), a single RMI call will call book() in my DBAdapter class on the server. The DBAdapter class will call lock(), read(), update(), unlock() all from the same thread.

Even if other threads "cut in" during its processing to do some of their own work, the other threads will all have different "identities" (i.e. corresponding Thread objects as Thread.currentThread()). When the thread scheduler decides to return to the original book() call, it will have the original Thread.currentThread() object.

Once the original book() call is finished, the thread will then be free to (possibly) take up another book() call. If this happens, nothing "bad" will happen (i.e. everything will lock(), unlock() fine, and no uncessesary exceptions will be thrown).

Michal.

Edit: removed double "Michal" signature at bottom
[ June 06, 2005: Message edited by: Michal Charemza ]
John Smith
Ranch Hand

Joined: Oct 08, 2001
Posts: 2937
MC: Nothing would go wrong if the same thread was used (as far as I can tell)

I thought you were planning to use currentThread() to identify the remote client. If so, I am presenting a scenario that may happen, depending on a particular RMI implementation. Since the RMI spec doesn't prescribe which thread should be used for the remote methoods invocations, it's quite possible that the same thread will be used for two different clients. To make it even worse, it can happen during the two concurrent invocations. Say you have to remote clients C1 and C2. Client C1 makes an RMI request, and RMI assigns thread T1 to it. In your lock() method running in that thread T1, you record that client C1 has a lock on record R1. At this moment, the RMI decides to allocate the CPU to client B who just made the request to book the same record R1. To preserve the resources, RMI temporarily dumps the state of thread T1 to disk, initializes it, and allocates that thread to client C2. Client C2 tries to lock record R1, but since it's locked already, it waits. In the meanwhile, RMI gives the CPU back to client C1 in a new thread T2. So client C1 moves on to book the record and enters the unlock(). Now you have a problem: since you recorded that thread T1 was the owner of that locked record, it would stay locked forever. Note that nothing in this scenario goes against the RMI specification, yet you violated your contract with Sun Microsystems.
Michal Charemza
Ranch Hand

Joined: Jul 13, 2004
Posts: 86
Originally posted by John Smith:

Since the RMI spec doesn't prescribe which thread should be used for the remote methoods invocations, it's quite possible that the same thread will be used for two different clients. To make it even worse, it can happen during the two concurrent invocations.
<<snip>>
RMI temporarily dumps the state of thread T1 to disk, initializes it, and allocates that thread to client C2
<<snip>>

Are you sure this can happen? I have only seen written that it is not guaranteed that the thread will be the same for different RMI calls (eg S&B p633). I don't think the senario you describe can happen for two reasons:

1. I feel as though it would have been written about in the books/discussions I have read, very close the the parts where it says that it is not guaranteed that the thread will be the same for different RMI calls. However, admittedly I have not read anywhere explicitely that what you describe won't happen, apart from...
2. It seems to go against the very idea of "thread of execution". From the general description of threads, for example in S&B starting p491, once book() is called in a thread, it will continue in that thread (albeit with possible interruptions when other threads are doing their work), until it is finished. The original call to book() will always use the same thread until it is finished.

What do you think?

Michal

Edit: removed random b
[ June 06, 2005: Message edited by: Michal Charemza ]
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
John:

The RMI spec does indeed guarantee that concurrent threads of execution will not have the same identity. Still don't believe it? Try it out yourself:

Generate about a 100 threads and have them wait on some condition. Each time, print out the thread ID...

It simply would violate the idea of a thread pool to attempt to reuse a thread that is already being used.

Reza
Lara McCarver
Ranch Hand

Joined: Dec 09, 2003
Posts: 118
I do not have any "cookie" parameters specified, like others do. I could not use the connection objects in this class - so I am back to whether I can design Data to assume that lock(), update() and unlock() are called from the same thread. From all the discussion, I think that I must do - I have no alternative (whether I use the naming ID trick or not).


I don't have cookie parameters either, but it is still possible to distinguish the client who is calling on the server side... so long as each client gets its own Data object. Then, each Data object can have a unique generated ID... at least, that is my design.
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Lara:

I have not yet fully explored the thick-client approach, but it sounds like what you are saying only applies to that. I would be glad to hear how the thick client approach overcomes the problem of the anonymous nature of RMI, short of registering RMI servers for each client request (highly inefficient in my view) or merely creating request (not client) specific instances of the Database (also pretty inefficient).

Note, using thick client also opens up a lot of other possibilities such as deadlock and stale locks that thin clients are not prone too.

If you want, I'd love to open up a separate thread on this, just let me know.

Reza

[ June 06, 2005: Message edited by: Reza Rahman ]
[ June 06, 2005: Message edited by: Reza Rahman ]
Michal Charemza
Ranch Hand

Joined: Jul 13, 2004
Posts: 86
Originally posted by Lara McCarver:

I don't have cookie parameters either, but it is still possible to distinguish the client who is calling on the server side... so long as each client gets its own Data object. Then, each Data object can have a unique generated ID... at least, that is my design.

Ah yes... I did consider a similar design but I'm not that keen on it. I suppose I don't like having many object when only one will do (making sure of course that having one does do).

Although come to think of it, I would think that a real life solution would probably need to uniquely identify the client, so I may change.

Michal
John Smith
Ranch Hand

Joined: Oct 08, 2001
Posts: 2937
LMcC: I don't have cookie parameters either, but it is still possible to distinguish the client who is calling on the server side... so long as each client gets its own Data object.

A variation of that is to use a single instance of Data object, but multiple instances of the Connection object (created by the server), on whose behav the RMI calls are made. The signature of lock()/unlock() doesn't need to change, but class Data would need to be aware of some other class that iether exposes itself as the identifier, or the class to which the lock() method delegates the locking. This is in contrast to Lara's design above where Data has enough knowledge to actually do the locking, because it's also the carrier of the client identity.
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
John:

I was waiting on Lara to explain this, but how many instances of the Data class are present in Lara's case? If you have the time, could you kindly express her design as well as yours in a diagram (I think that is allowed)...thanks in advance.

Also, if I understand correctly, you are essentially passing the client's identity to the connection object for each method invocation? Otherise you'll simply be resorting to creating a connection object for each client request, yes?

Again, I will be happy to open up a new thread on the topic since this one is getting a little too large...

Reza

[ June 06, 2005: Message edited by: Reza Rahman ]
[ June 06, 2005: Message edited by: Reza Rahman ]
John Smith
Ranch Hand

Joined: Oct 08, 2001
Posts: 2937
Lara is out shopping, but here is what she is thinking (I deliberately made it sketchy so that Lara doesn't feel like her efforts all have been wasted):



This design matches her beauty, with one exception that Michal (it's never too late to insert an "e" into your display name) pointed out above: one fully expects that one instance of Data is more than enough for all remote clients.

The alternative design that I refered to uses a single instance of Data, but the drawback is that the lock()/unlock() methods of Data are empty. The locking is done somewhere else. I can't believe I was able to pull this trick on Sun, but it worked out to the full credit on the server design. It's a drawback in a sense that it seems to violate the requirements, but I like to think of it as an advantage of having Data class be very pure and free of fluff.

Finally, here is the Applying the Factory Pattern to RMI link that both Lara and I like to revisit before we call it a day.
[ June 06, 2005: Message edited by: John Smith ]
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
John:

Would you be so kind as to open this on a separte thread so we can discuss the pros and cons of this approach? I am very impressed by the hard-work required to design the diagram!! You are more than a worthy debate partner (I know you don't like me calling you partner or friend but it's a free Internet, right)

As an side, I think it is best to discuss this at a high level to avoid giving away too much (the existing books on the topic are a good guide - lets discuss this in general client/server programming terms)...

Incidentally, for anyone who might be interested, here is a little more discussion on the [ UD: removed link to copyrighted material ] implemenation of RMI factories. The provided code "binds" instead of "exports", but exporting is not that much different or harder (think of export as "anonymous" bind)...

Reza

P.S.: Jokes aside, I wonder if making personal comments is appropriate to the general atmosphere of a forum hopefully full of professional (or would-be professional) developers (unless Lara happens to be your wife, girlfriend, sister, etc)...

[ June 07, 2005: Message edited by: Reza Rahman ]
[ August 03, 2007: Message edited by: Ulf Dittmer ]
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Hi all:

I created a new topic to continue the discussion on the pros and cons of the thick/thin client approach here for all who are still interested. Thanks for participating.

Reza
[ June 07, 2005: Message edited by: Reza Rahman ]
Frans Janssen
Ranch Hand

Joined: Dec 29, 2004
Posts: 357

P.S.: Jokes aside, I wonder if making personal comments is appropriate to the general atmosphere of a forum hopefully full of professional (or would-be professional) developers (unless Lara happens to be your wife, girlfriend, sister, etc)...

Johns jokes are indeed probably not appropriate, but I did think they were funny. He managed to have me sitting behind my monitor with a smile on my face!

Frans.


SCJP 1.4, SCJD
Lara McCarver
Ranch Hand

Joined: Dec 09, 2003
Posts: 118
Thanks for the fantastic pictures, John though of course what was even more priceless was your comments

Lara is out shopping


Just so you know, I was out shopping for a software package so I would no longer have to resort to those ugly ASCII diagrams!

...

This design matches her beauty


I can only say:
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Frans/Lara/John:

I would very much enjoy your kind participation in the new topic I opened up, provided you have an interest in it. I think many others including myself would benefit from it. Thanks.

Reza

P.S.: Please don't take this the wrong way - I mean this with the utmost respect, I can't help but find these exchanges between complete strangers that apparently know each other a little uncomfortable (maybe that's just my background, but I suspect others would feel the same way...please remember others (like me) are reading this and we are not in a private chat room)...
[ June 07, 2005: Message edited by: Reza Rahman ]
Lara McCarver
Ranch Hand

Joined: Dec 09, 2003
Posts: 118
I'm confused. When I followed your link, I got this topic: "Pros And Cons Of Thick Client/Thin Client". But the current thread is on lock(), update(), and unlock() and how many threads are needed. Did you post the wrong link, or is that what you were interested in all along?
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Lara:

The link is indeed correct, sorry for not making it a bit clearer. Just to clarify:

I think Michal is more interested in this topic (if he is any longer), I am more interested in the thin/thick client architecture overall (if you follow the thread, this thread peaked my interest in it)...

Again, I understand everyone has limitations of time and interest. Feel free to avoid the topic if it does not interest you at the current time, but I was hoping I would get the people on this post interested in it...however, maybe that isn't a good idea with the background of this thread...

Reza
[ June 07, 2005: Message edited by: Reza Rahman ]
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Lara:

Thanks for pointing that out. I corrected the link posting.

Reza
Lara McCarver
Ranch Hand

Joined: Dec 09, 2003
Posts: 118
I have to apologize because... blush... flattery will get you everywhere... and so I didn't scrutinize the fine print on John's beautiful diagram.

I actually have multiple RMI servers, one per client, with each Data object created by a separate RMI server. But the design John shows, where there are multiple Data objects but only 1 RMI server, is also a good way to go, maybe better! (I have to think about it.)

When I first read about the multiple-RMI-server design idea in "Java RMI", I was a little skeptical. And then, it was repeated in the Habibi book. There is a chapter in the "Java RMI" book where the author discusses the pros and cons of multiple RMI servers vs. one RMI server. Because RMI handles connection pooling (i.e. different servers can use the same underlying connection), it didn't sound like there was a big performance impact either way, so I just went with the multiple server approach and didn't think too much about it. If people on this forum have heard otherwise, that a multiple-RMI-server design has big performance issues, I would be interested to hear it.

Second, in terms of having the Data object know what the client identity is, for this assignment, it isn't actually necessary for the client to "pass itself" to the Data object on each and every method call, or even to the Data factory. All that is needed is for the client to be associated with a unique and persistant Data object.

Think of it this way: you go to get a driver's license and the DMV (Department of Motor Vehicles) issues a Driver's License ID. Now for all your records, it can use your ID. Of course the DMV actually keeps track of the correspondence between you (where you live, etc.) and your driver's license number, but the server doesn't need to care about that. It just cares that it has a unique ID to use for its operations.

I think in a real world application, it would be useful for each client to have an "identity" (like a user name) and that could samehow be used to create the client ID on the server side, and then used in logging, and also in an audit trail of all database operations.

But in this application, the Data object doesn't really need to know any of the personal details about the client. The reason I happen to care about having this ID is because I have no lock cookies, so if I did not have the client ID, then when the client called unlock(), I would not know if it is the same client that previously called lock().
Reza Rahman
author
Ranch Hand

Joined: Feb 01, 2005
Posts: 580
    
    5
Lara:

Are you sure RMI has a shared connection pool across remote object references? I always thought each remote skeleton listens on its own port...do you happen to have a reference for this behaviour? If not, it is no big deal, I'll check this for both you and myself.

I do agree, if you are using remote references via either rebind or export, you do not need a separate client identifier. Otherwise, a client identifier is the only way you can get around the anonymous nature of RMI.

Thanks for the detailed reply.

Reza
[ June 07, 2005: Message edited by: Reza Rahman ]
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: B&S: OK to assume lock(), update(), unlock() called from same thread?