Regards<br />Prem<br />SCJP, SCJD, SCWCD, SCBCD, SCEA, SCJDWS
SCJP 1.4, SCJD
Originally posted by Surya Kumar:
How extensive the locking system supposed to be? It carries a full 80 marks? I tried to implement it with wait/notify. The code is very compact (around 100 lines)
Anton Golovin ([email protected]) SCJP, SCJD, SCBCD, SCWCD, OCEJWSD, SCEA/OCMJEA [JEE certs from Sun/Oracle]
What you thought was right today may need a refactoring tomorrow...
Originally posted by Mike Vess:
It is not possible to make sure that the user that have locked the record is the same that calls update/delete or create. I have decided to make it optional to use the locking in the interface and it is possible to call update/delete on a record that is not locked.
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Originally posted by Mike Vess:
100 lines of code for synchronization? In my DBMain interface the methods look like this:
public void lock(int recNo) throws RecordNotFoundException;
public void unlock(int recNo) throws RecordNotFoundException;
public boolean isLocked(int recNo) throws RecordNotFoundException;
It is not possible to make sure that the user that have locked the record is the same that calls update/delete or create. I have decided to make it optional to use the locking in the interface and it is possible to call update/delete on a record that is not locked.
Anton Golovin ([email protected]) SCJP, SCJD, SCBCD, SCWCD, OCEJWSD, SCEA/OCMJEA [JEE certs from Sun/Oracle]
Anton Golovin ([email protected]) SCJP, SCJD, SCBCD, SCWCD, OCEJWSD, SCEA/OCMJEA [JEE certs from Sun/Oracle]
implementing a private method isLockedByCaller(int recNo, long cookie); should solve the identification issue.
What you thought was right today may need a refactoring tomorrow...
SCJP, SCJD, SCWCD.
What you thought was right today may need a refactoring tomorrow...
Originally posted by Mike Vess:
I does not matter weather or not i have an unique object for each client that connects to the server. The problem is that the interface provided by sun not makes it possible to make sure that it is the same client that lockes the record that then updates or deletes it.
public void lock(int recNo) throws RecordNotFoundException;
public void unlock(int recNo) throws RecordNotFoundException;
public void update(int recNo, String[] data) throws RecordNotFoundException;
In the update method i can�t tell if it is the same client that have called the lock method and another question is what i should do in update if the record not is locked? Call lock method if it is not locked or throw RecordNotFoundException (which would be silly) or throw a RuntimeException (which also would be silly) or just ignore if the record is locked or not and just do the update.
Anton Golovin ([email protected]) SCJP, SCJD, SCBCD, SCWCD, OCEJWSD, SCEA/OCMJEA [JEE certs from Sun/Oracle]
The interface does not, sure. But your implementation of lock and unlock and update methods in Data class may call private methods of same class, which are not exposed via your interface. There are no problems identifying the correct client.
What you thought was right today may need a refactoring tomorrow...
What you thought was right today may need a refactoring tomorrow...
Originally posted by Mike Vess:
What does private method help me with? How can you say there is no problem identifying the client when the client only uses the methods defined in the interface?
Anton Golovin ([email protected]) SCJP, SCJD, SCBCD, SCWCD, OCEJWSD, SCEA/OCMJEA [JEE certs from Sun/Oracle]
What you thought was right today may need a refactoring tomorrow...
Originally posted by Mike Vess:
My interface looks like this:
public void lock(int recNo) throws RecordNotFoundException;
public void unlock(int recNo) throws RecordNotFoundException;
Note that there is NO COOKIE value. Some of my collegies have another version of the interface with a cookie value but my interface don�t. If i had the version with a cookie value i would have no problem at all to solve to locking issue.
Anton Golovin ([email protected]) SCJP, SCJD, SCBCD, SCWCD, OCEJWSD, SCEA/OCMJEA [JEE certs from Sun/Oracle]
public String book(int recNo) {
final int recordNumber = recNo;
db.lock(recordNumber);
db.update(recordNumber, ...);
db.unlock(recordNumber);
}
What you thought was right today may need a refactoring tomorrow...
then, to determine if it is ok to call those methods, I would call for locking:
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Originally posted by Mike Vess:
I does not matter weather or not i have an unique object for each client that connects to the server. The problem is that the interface provided by sun not makes it possible to make sure that it is the same client that lockes the record that then updates or deletes it.
public void lock(int recNo) throws RecordNotFoundException;
public void unlock(int recNo) throws RecordNotFoundException;
public void update(int recNo, String[] data) throws RecordNotFoundException;
In the update method i can�t tell if it is the same client that have called the lock method and another question is what i should do in update if the record not is locked? Call lock method if it is not locked or throw RecordNotFoundException (which would be silly) or throw a RuntimeException (which also would be silly) or just ignore if the record is locked or not and just do the update.
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Originally posted by Andrew Monkhouse:
Hi Mike,
But if you had a unique instance of the Data object for each connected client, then you could use the instance of the Data object itself as the client identifier.
That is, in the lock() code, you can store this in your map of who owns what lock, and in your update method, you can compare this with the owner of the lock - make sure they match.
Regards, Andrew
Originally posted by Mike Vess:
As i said before the locking is not at all needed if all access to the database is thread safe.
Anton Golovin ([email protected]) SCJP, SCJD, SCBCD, SCWCD, OCEJWSD, SCEA/OCMJEA [JEE certs from Sun/Oracle]
Originally posted by Andrew Monkhouse:
Hi Anton,
Two questions:Why are you calling notifyAll() in your locking method? (Who are you notifying, and what are you notifying them about?) Are you sure that you are handling InterruptedException correctly? (What can cause this exception to be thrown? What state will your program be in then? What should you do from there?)
Regards, Andrew
Anton Golovin ([email protected]) SCJP, SCJD, SCBCD, SCWCD, OCEJWSD, SCEA/OCMJEA [JEE certs from Sun/Oracle]
Anton Golovin:
I completely agree with you. I do think, though, that the assignment is pushing us to cache the records because then locking would be necessary. I was originally going to implement direct io access, but then, if I lock the datafile, I did not need locking. The only solution was to use a cache.
Andrew Monkhouse:
But if you had a unique instance of the Data object for each connected client, then you could use the instance of the Data object itself as the client identifier.
Anton Golovin:
I was thinking in this way: if the thread is going to go to wait, how are other threads going to know to grab control? Maybe I misunderstand something.
What you thought was right today may need a refactoring tomorrow...
Anton Golovin ([email protected]) SCJP, SCJD, SCBCD, SCWCD, OCEJWSD, SCEA/OCMJEA [JEE certs from Sun/Oracle]
Locking is necessary because client A and client Z may both be going for record Q, however, the record Q may be deleted, rewritten in the time they get to it.
What you thought was right today may need a refactoring tomorrow...
Originally posted by peter wooster:
This sounds like a very good way to proceed, I'm assuming that the clients have a way of uniquely identifying themselves, such as a client id obtained the first time they issue a command over the network and used afterwards to get the Data instance from a Map.
On the first command the client could provide clientID=-1 and the network code would create a new clientID and register it in the Map with its Data instance. On later commands the client would use the provided id to recover thier Data instance.
Andrew, is this what you meant, or is there a better way to identify the client?[/QB]
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Originally posted by Mike Vess:
This will probably work but it�s not nice:
As i said before the locking is not at all needed if all access to the database is thread safe.
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Originally posted by Andrew Monkhouse:
Why are you calling notifyAll() in your locking method? (Who are you notifying, and what are you notifying them about?)
Originally posted by Anton Golovin:
I was thinking in this way: if the thread is going to go to wait, how are other threads going to know to grab control? Maybe I misunderstand something - threading is very difficult for me - but that is what I was thinking.
This is a common mistake - when two threads both try to access code within a synchronized block, one will get access, and the other will go into blocked state. Not wait state. The only way to enter wait state is by explictly calling one of the wait() methods.
When you call notify() or notifyAll() you are only notifying threads that are in wait state that they should wake up and try to reaquire the monitor (or mutex (Mutual Exclusion) lock) for the object you are synchronizing on (which they will fail to do since your thread is still in the synchronized block - therefore after waking, they will effectively go to blocked state.
Once your thread releases the monitor on the synchronized object, the JVM will pick one of the threads that is blocked for that monitor, and allow it to continue processing. All other threads will remain in the blocked state.
Going into wait state automatically releases the monitor on the synchronized object.
Lets try and do this as a concrete example. Three threads all try to gain a lock on record # 1 at the same time:
Thread A gets the monitor for the synchronized block's object (this) Thread B cannot get the monitor - enters blocked state Thread C cannot get the monitor - enters blocked state Thread A locks record 1, then leaves the synchronized block - thread B is no longer blocked Thread B gets the monitor Thread C remains blocked Thread B tries to lock the record, calls notifyAll() (nobody waiting, so no effect), and goes into wait state (releasing the monitor) Thread C gets the monitor Thread C tries to lock the record, calls notifyAll() (waking thread B which goes back into blocked state), goes into wait state (releasing the monitor) Thread B gets the monitor Thread B tries to lock the record, calls notifyAll() (waking thread B which goes back into blocked state), goes into wait state (releasing the monitor) ...
Because of that call to notifyAll(), the two threads that are waiting will keep waking each other up forever - consuming a lot of CPU cycles in the meantime.
Without that call to notifyAll(), both threads B and C will go into wait state, and consume no CPU cycles until the unlock() method calls notifyAll() when a record is unlocked.
As with everything - what I wrote may make perfect sense, or it may not make any sense at all. If the later is true, then you might want to look at the J2SE API documentation for the Object class, specifically the wait(), notify() and notifyAll() methods. Or look at any other book detailing threading.
Originally posted by Andrew Monkhouse:
Are you sure that you are handling InterruptedException correctly? (What can cause this exception to be thrown? What state will your program be in then? What should you do from there?)
Originally posted by Anton Golovin:
For the second question, I was sending control to the top of the loop to keep checking if the record is unlocked.
I can see that you will be going back to the top of the loop. The question here is - who is throwing this InterruptedException, and why are they doing it? If you are throwing that Exception, then you may be right in resuming the loop. But if you are not throwing it, then who has thrown it? If you don't know who is throwing it, then can you be sure that you are safe to just resume the loop?
Regards, Andrew
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Originally posted by Andrew Monkhouse:
But if you had a unique instance of the Data object for each connected client, then you could use the instance of the Data object itself as the client identifier.
Originally posted by Mike Vess:
I agree with you there but the implementation would not be nice. Here you would have to have a static HashMap of locked records and a static File instance for database access and another drawback with this solution is that you won�t be able to use the dataclass to connect to separate databases in the same jvm because of the static variables.
The Sun Certified Java Developer Exam with J2SE 5: paper version from Amazon, PDF from Apress, Online reference: Books 24x7 Personal blog
Originally posted by Andrew Monkhouse:
Hi Peter,
That is an easy way of doing things. Another alternative is by Applying the Factory Pattern to RMI.
If you are an EJB Session Bean programmer, you should already be familiar with this basic concept: the Home interface is basically a factory - you use that to create() the real EJB - of which there is one per client. Obviously, if there is one Session Bean per client, then it can have it's own private instance of whatever it needs as well.
Back in the old Fly By Night Services assignment, this was the most common way of solving the problem we were given: we did not have cookies, and the client had to call the add(), modify(), delete(), and read() methods.
Regards, Andrew
Anton Golovin ([email protected]) SCJP, SCJD, SCBCD, SCWCD, OCEJWSD, SCEA/OCMJEA [JEE certs from Sun/Oracle]
Thanks for clearing that up Andrew. I generally understood the locking process, but your explanation made it much more understandable for me.The logical record locking and having thread safe access to the data file serve two totally different purposes.
“Programming today is a race between software engineers striving to build bigger and better idiot-proof programs, and the Universe trying to produce bigger and better idiots. So far, the Universe is winning.” - Rich Cook
Did you see how Paul cut 87% off of his electric heat bill with 82 watts of micro heaters? |