• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Nested locks required

 
Simon Cockayne
Ranch Hand
Posts: 214
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi,

I am doing B&S...

// 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;

...I've read a lot of discussion of people describing a HashMap to store mapping of record number and record lock information (e.g. client Data instance).

Typically in this scenario there is a lock object e.g. MasterLock.

Access to the HashMap is syncrhonized on the MasterLock...then if the client does finds the pertinent record is locked it can just do a MasterLock.wait().

Then when another client unlocks the pertinent record it can call MasterLock.notify()...and hey presto the first client can wake up, grab the lock on the record and continue.

But...the flaw here is that if the second client is unlocking a DIFFERENT record, the first thread will still potentially get woken up...by the MasterLock.notifyall()...grab the MasterLock lock...(even though the record it is interested is still locked, which breaks the instruction in the unlock method).


A solution then would be for the first client to synchronize, and potentially wait, on an object related to the specific record it is waiting on...which is easily done.

But...since we also don't want anyone updating the HashMap in an unsynchronized manner...we still need to synchronize on that...

I can implement the solution in a snap with nested locks...but everyone seems to pooh-pooh nested locks with a passion.

Thoughts???

Cheers,

Simon.
 
Edwin Dalorzo
Ranch Hand
Posts: 961
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I do not see a real problem on this, you know that your wait() must be invoked in a loop:



Therefore, although you use notify all, when the condition is again evaluated, the thread gets back to the waiting state if its record is still locked.

To minimize the impactt of this you could use notify() instead of notifyAll() to make sure that just one thread is notify.

Now, to ensure that all threads ever get notified if you are using JDK 1.5 you may want to use a ReentrantLock with fairness set to true.
 
Simon Cockayne
Ranch Hand
Posts: 214
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Edwin,

You say:
Therefore, although you use notify all, when the condition is again evaluated, the thread gets back to the waiting state if its record is still locked.


BUT, the unlock interface states:

...the current thread gives up the CPU and consumes no CPU cycles until the record is unlocked.


So...clearly if the thread is woken up (caused by a MasterLock.notify(), triggered by a different record being unlocked) then our thread IS consuming CPU cycles (even if that is just to check the condition and realise its record is NOT unlocked and wait again) but since its record has NOT been unlocked...that has broken the spec, right?

Cheers,

Simon
 
Simon Cockayne
Ranch Hand
Posts: 214
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Edwin,

Bingo!

I've now got a virtual waste paper basket full of ropey old 1.4 synchronization code

...and instead...

a brand spanking new locking mechanism based on J2SE 5.0 the ReentrantLock class.

It is SO much cleaner...AND...I can now, with joy, fully support the proper B&S lock spec to the letter.

Cheers,

Si
 
Liviu Carausu
Ranch Hand
Posts: 160
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Simon,

Can you please explain in more detail your Bingo ?

How it will help the usage of the Java 5.0 ReentrantLock to wake up exactly
the thread that waits for the record that was unlocked ? Or do you mean to have a Condition object associated with each entry in the Map ?

Thanks in advance ,

Liviu
 
Simon Cockayne
Ranch Hand
Posts: 214
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Liviu,

Yes you surmise correctly.

Have a HashMap recordLocks: mapping key is wrapped a recNo. Mapping value is a RecordLock object.

A RecordLock class extends ReentrantLock and has a reference to the recordLock owner and a reference to a unique condition.

Ergo, any thread that wants to wait on the recordlock (so it can update the owner informaiton) can call theCondition.await().

And any thread that has finished with a recordLock (having unlocked it say) can call theCondition.signal().

Andrew Monkhouse's book illustrates the theory very nicely.

Cheers,

Simon
 
Liviu Carausu
Ranch Hand
Posts: 160
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Simon,

I'm so stupid that I cannot find this theory in Andrew Monkhouse's book.

I mean this with the collection of Condition objects. Can you please be so

kind and give me some page numbers ?

Thank you very much !

Greetings,
Liviu
 
Simon Cockayne
Ranch Hand
Posts: 214
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Liviu,

I reccomend you read chapter 5.

Actually, I reccomend you read the whole book...it is very good.

Cheers,

Simon
 
Liviu Carausu
Ranch Hand
Posts: 160
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Simon,

I have read the Multiple Notification Points discussion from SCJD book.

There, another solution is also mentioned (without source code example): "Under Jdk5 you can have all your threads obtain a lock on the same object but use different Conditions upon which they should be notified".

This solution looks cleaner to me because it does not use a lock for each condition.

What do you think ?
 
Simon Cockayne
Ranch Hand
Posts: 214
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Liviu,

Give it a whirl!

Simon
 
Mihai Radulescu
Ranch Hand
Posts: 918
IntelliJ IDE Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Simon

The old notifyAll works perfect in this case, more the specifications :

Any attempt to lock a resource that is already locked should cause the current thread to give up the CPU, consuming no CPU cycles until the desired resource becomes available.


said that to lock a thread which tries to access a locked resource, and you do this. If the resource is free you can wake up all the threads (and let them consume CPU cycles) because the resource is free. If the first thread lock the resource the the scenario is happen over and over again.

Regards M.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic