_ _ ________________________ _ _ <br /> <br />Just SCJP (but 93%)
SCJP, SCJD, SCWCD, OCPJBCD
_ _ ________________________ _ _ <br /> <br />Just SCJP (but 93%)
Originally posted by Mandy Bowman:
i have no idea about this. As far as I can see this seems too complicated to me. I always just use a synchonrised block. i have no idea about how to do these things with reentrant locks and all that. what does everyone else thing is it better to use the old way of doing it or use these new locking classes?
_ _ ________________________ _ _ <br /> <br />Just SCJP (but 93%)
Originally posted by rinke hoekstra:
After having read threads about locking on this forum for several weeks, doubting, reading threads again, etc, etc, I eventually had the guts to create my own locking strategy and lock method.
Please consider my method, and please see my questions below it.
General Strategy:
Data class implements given interface by sun, and is a Facade delegating tasks to two singleton classes: DataAccess and LockManager.
In DataAccess all methods which do read or write from the database have a synchronized block inside them (Create, Read, update, delete, find).
LockManager has a private ReentrantLock, a private Condition, and a HashMap with Integers (recordnumber) and Longs (the cookie). The HashMap is created via Collections.synchronizedMap.
I'm not using any data caching.
The lock method looks like this:
Questions on this:
General: Is this strategy OK you think?
//1: the call to lock.await normally is inside a try / catch block for an InterruptedException. I'm doubting what to put inside this catch clause.
//2: Note that there is no call to signalAll(). This is only done at unlocking in the unlock method. Is that sound?
3: I'm having doubts between using ReentrantLock or just using a synchronized block in stead of it, synchronizing on the RandomAccessFile object. Apparantly the code doesn't change much because of such a change. I was wondering what are peoples arguments for one or another. My own thinking would be that ReentrantLock is a bit more clear for novice programmers.
4: For a completely differnt approach: I saw someone mentioning "lockable object pattern", but I couldn't find much on the net about it. Anyone knows if this is a good approach, and how it works??
Thanks in advance.
[ June 10, 2007: Message edited by: rinke hoekstra ]
SCJP, SCWCD, SCBCD, SCJD, BB Java2 and JSP1.1
... //check if exists, throw RecordNotFoundException if not
... //add to the map
My question is: how are you going to check "check if exists" ? will you have a reference to your FileAccess class from LockManager class ? or I got something wrong here ... Thanks
Gabriel Vargas
SCJP, SCJD, now studying for SCWCD and working to be a better person
Originally posted by Dimirti Slyus:
Hi ! My first post here...
The code is from your LockManager class, right ?
My question is: how are you going to check "check if exists" ? will you have a reference to your FileAccess class from LockManager class ? or I got something wrong here ... Thanks
SCJP, SCWCD, SCBCD, SCJD, BB Java2 and JSP1.1
_ _ ________________________ _ _ <br /> <br />Just SCJP (but 93%)
Gabriel Vargas
SCJP, SCJD, now studying for SCWCD and working to be a better person
Originally posted by rinke hoekstra:
Dimitri brings up an issue that I'm wrestling with too. I think it is not so easy, or maybe I'm missing things?
In fact, we have to check if the record exists, and this must be done from inside the synchronized (or locked) code, otherwise it makes no sense because another thread could creep in and spoil it all.
So what Ken and Gabriel are suggesting is something like this (if I understand it well):
Data class implements DB, and has a lock method.
1 - starts with ReentrantLock.lock (meaning that the ReentrantLock object is in the Data class and not in LockManager???)
2 - this lock method calls LockManager.lock,
3 - LockManager.lock checks if Map contains the record,
-> if yes, wait.
-> if no, return
4 - then Data checks FileAccess if the record exists,
5 - then Data calls LockManager.add (or something like that) to add the record to the map
6 - and then the Data.lock calls ReentrantLock.unlock
It seems to me that this is pretty complicated, as a DataAccess call is right in the center in between all kind of stuff which should belong in the LockManager.
It would be much more simple if the (singleton) constructor of LockManager is passed a reference to FileAccess, so FileAccess is always available at its use, and the simple check if the record exists can be done from within the LockManager.lock method without this up and down going.
Would this really spoil "the objective of separating the functionality of the two classes", as Gabriel puts this?
Or is it even better to conclude that locking functionality and Data access functionality are so intermingled, that the most simple sollution is just NOT to separate them and put them all simply in the Data class, which then stops being a Facade???
Or am I thinking too complicated this late at night, and am I missing something completely???
SCJP, SCWCD, SCBCD, SCJD, BB Java2 and JSP1.1
_ _ ________________________ _ _ <br /> <br />Just SCJP (but 93%)
_ _ ________________________ _ _ <br /> <br />Just SCJP (but 93%)
Originally posted by rinke hoekstra:
[QB]So, if I get it right, your sollution is:
just ignore the RecordNotFoundException in the lock method, as it is bullshit anyway, and put this motivation in choices.txt. And DON't check if the record exists inside the lock method.
// Creates a new record in the database (possibly reusing a
// deleted entry). Inserts the given data, and returns the record
// number of the new record.
SCJP, SCWCD, SCBCD, SCJD, BB Java2 and JSP1.1
If you don't allow to lock deleted record entry then how you will do this
quote:
// Creates a new record in the database (possibly reusing a
// deleted entry). Inserts the given data, and returns the record
// number of the new record.
Now the question of throwing recordnotfoundexception in lock/unlock method I throw them if record number passed is invalid not that they are deleted. I mean consider hypothetical situation in direct test of Data class and some client pass invalid record number i.e. -1000 or something like that will never exist for locking so Recordnotfoundexception thrown and same client also go for update or delete and unlock with invalid cookie. In that case you throw RNFE in unlock and update or delete methods.
_ _ ________________________ _ _ <br /> <br />Just SCJP (but 93%)
Originally posted by rinke hoekstra:
Hi Ken,
thanks for your reply.
Yes, I can see that point. But strictly seen, this check would not even be necessary as I argued above, as the next called method in line (delete, update) will perform this check too, and throw that exception too.
Would it go to far if I'm saying that we are basically throwing the RecordNotFoundException in lock / unlock just for the sake of throwing it because it is in the interface contract?
SCJP, SCWCD, SCBCD, SCJD, BB Java2 and JSP1.1
Originally posted by Dimirti Slyus:
Hi guys! sorry I was not here for couple of days.
Here is my lock method of the Data class:
public long lock(int recNo) throws RecordNotFoundException {
long cookie = lockManager.lock(recNo);
boolean recordExist = database.exist(recNo);
if (recordExist) {
return cookie;
}
else {
lockManager.unlock(recNo, cookie);
throw new RecordNotFoundException();
}
}
where:
lockManager.lock(recNo) generates random cookie number, adds the entry into the map or waits if the record is locked.
database.exist(recNo) just checks if record exsists and not deleted.
do you see any potential holes in here ? Thanks
SCJP, SCWCD, SCBCD, SCJD, BB Java2 and JSP1.1
how you will create new record by reusing deleted entry? as of now you are not allowing to lock deleted record. If you don't lock deleted record (e.g. 11) two threads can create new record at same record i.e. 11 .
Originally posted by Dimirti Slyus:
Thanks for your post, Ken.
Agree but creating the record does not require locking. I will explain.
Let's say CLIENT_1 calls Data.create method.
The Data class will call database.create method
My database class has cached deleted records. So the database.create will:
1. Lock the cache.
2. check if there is deleted record in cache. If it is it will use the recNom for writing the record. If not it will use the last record +1.
3. synchronize on the database and write the new record.
4. delete entry from deleted records cache.
5. Unlock the cache and return recNo.
CLIENT_2 will try to create record by calling the same Data.create that will call database.create.
Now it will stop waiting for the lock to be released from the 1st step. After cache is released it will not contain deleted record used by the first client. Therefore this client will use another record or new one - step 2.
Did I miss anything ?
SCJP, SCWCD, SCBCD, SCJD, BB Java2 and JSP1.1
SCJP(94%)
SCJP(94%)
SCJP(94%)
Originally posted by Ziji Zhang:
Dimirti,
I am thinking of doing the similar approach for create method,
If you keep a list of deleted record,
there are two issues that I am worried about
1. you are facing nested locking, in create, you first lock the deleted Record List, then you lock the data file.
2. in deleted method you again will do nested locking, add deleted
record into the list.
Ziji
Oracle Certified Master Java SE6 Developer(SCJD),
OCE JEE 6 JSP and Servlets Developer,
Java EE6 Java Server Faces Developer.
Tell me how it all turns out. Here is a tiny ad:
Gift giving made easy with the permaculture playing cards
https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
|