File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Developer Certification (SCJD/OCMJD) and the fly likes Singleton Data class - locking on the locked records map Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Developer Certification (SCJD/OCMJD)
Bookmark "Singleton Data class - locking on the locked records map" Watch "Singleton Data class - locking on the locked records map" New topic
Author

Singleton Data class - locking on the locked records map

alan dunne
Greenhorn

Joined: Jan 05, 2012
Posts: 6
Hi guys,

I'm pretty sure this topic has been covered before but I can't quite find how to solve it. If someone could help me (or point me towards another relevant thread) it would be great. My project is URLyBird 1.2.2.

Basically I am using the Singleton Data class with all synhronized methods. Behind this I am using a package level RoomDataController class that does the work (facade). This class controls the access to the DB (using another helper class), the caching of records on startup and writing the cache back to the DB on shutdown.

My problem is that as I am using all synchronized methods once lock() has been called on a record that is already locked the running thread will never be notified of the lock being released at it is the only thread allowed to run (I hope this makes sense).

So, within my RoomDataController I have a static map containing locked records. The lock method populates this. When this method is called again it will wait() as the record is locked. However unlock() can never be called because of the synchronization of all methods.

Again, apologies if this has been discussed before, but I couldn't find a (completely) relevant thread. Also, has anyone any thoughts on the design - using a singleton with a facade and a cache?

Thanks.
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 5599
    
  15

Hi Alan,

Are you familiar with how wait / notify / notifyAll work? From your question I would guess you are not. Maybe you should familiarize yourself with these methods, how they work and interact, what happens when you invoke one of them,... if you do, your question will solve itself. Good starting points would be the Object class and Oracle's Concurrency tutorial.

Kind regards,
Roel


SCJA, SCJP (1.4 | 5.0 | 6.0), SCJD
http://www.javaroe.be/
David Byron
Rancher

Joined: Jan 20, 2009
Posts: 172

In addition, the book Java Threads-- old but very good-- may be had in used condition for pocket change.


OCMJD 6, OCPJP7, Baroque Potion, G+
Himai Minh
Ranch Hand

Joined: Jul 29, 2012
Posts: 813
    
    1
Hi, Alan.
I am not sure if I understand your question.
Yes. You can synchronize all the methods in data class as suggested by Roberto. In this forum, download Roberto Perillo's paper about passing this exam.

The lock method does locking a record when one thread is making a room reservation. When this thread locks this room, it updates the room reservation record. After that, this thread unlocks the room.
Lock and unlock will prevent two threads making the same room reservation.

Hint :
lock (){
while (isLocked(roomNumber)){

try{
room.wait(); // wait for this room object
}
catch (...){ ...}
}

}

unlock(){
try{
room.notifyAll(); // notify all threads which are waiting for this room
}
catch (...){....}
}

This is a suggestion, in the GUI, once you hit the "reserve" button, you call the reserve() method. The reserve method implements these lock() ; update(); unlock (); once you hit the button.
You can create a few threads that try to call the the reserve method and see if you run into deadlock or run the update() method at the same time.

You can read Apress's SCJD study guide from Andrew Monkhouse and Terry Camerleno and read Robert Perillo's test class.

Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 5599
    
  15

Himai Minh wrote:Lock and unlock will prevent two threads making the same room reservation.

That's not completely true. To prevent same room reservation you need extra business logic when booking a room. Lock and unlock methods prevents threads overwriting each other's data.
alan dunne
Greenhorn

Joined: Jan 05, 2012
Posts: 6
Hi Roel,

Thanks for your reply. I'm aware of the wait() notify() and notifyAll() methods. My problem is that once the lock() method is called by the second thread (in an attempt to lock a record already locked by the first thread) the wait() method is called from inside the synchronized(lockedRecordsMap){} block. That's fine.

However, as the methods in my Data class are all synchronized the update() and lock() methods cannot be called by the thread which owns the lock as the second thread is within the lock() method still and this must complete before another method can be called.

I have debugged this several times and I get deadlock in this situation.

Again, any help would be appreciated.

Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 5599
    
  15

From the javadoc of the wait()-method:
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method.


So when a thread has to wait, it releases the lock (object's monitor). I don't get why the other thread could not acquire the lock and perform update and unlock. So if it's deadlocking there's definitely another issue.
alan dunne
Greenhorn

Joined: Jan 05, 2012
Posts: 6
Well it releases the lock on the lockedRecordsMap, but as I am calling:

lock()
update()
unlock()

the first thread cannot call update() as the second thread is waiting in the lock() (synchronized) method, which owns the lock on the Data instance.

The first thread cannot access this instance as wait() only releases the (static) lockedRecordsMap, not the Data instance...

As the three methods are synchronized on the Data instance, i really should not have to synchronize on the lockedRecordsMap as well. But then how do I notify the second thread that the record has been unlcoked() as notify must be called from a synchronized block?

Thanks for your help.
Himai Minh
Ranch Hand

Joined: Jul 29, 2012
Posts: 813
    
    1
Maybe, provide us your psuedo code and see why you have a deadlock. Are you sure you are locking on the same object? I guess your 1st thread locks on an object a , but 2nd thread wait for another object ,b. 1st thread notifies all other threads which waits for its object,a . 2nd thread waits for b forever.


1. First thread locks on a single object
2. Second thread waits for this object while this object is locked.
3. First thread updates this single object.
4. Second thread is notified and won't wait.

Deadlock may happens if you have this:
synchronize (a) {
synchronize (b){
....
}
}
and
synchronized (b){
synchronized(a){
....
}

}
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 5599
    
  15

alan dunne wrote:As the three methods are synchronized on the Data instance, i really should not have to synchronize on the lockedRecordsMap as well. But then how do I notify the second thread that the record has been unlcoked() as notify must be called from a synchronized block?

You have a singleton Data class with all synchronized methods and you worry that you can't call notify from a synchronized block

Let's take a look at the following 2 code snippets




These are semantically equivalent! So if you use a synchronized method, you have a synchronized block to call wait/notify/notifyAll from. Synchronizing on 2 different objects (this & lockedRecordsMap) can be very dangerous and result in deadlock situations. Use it only when necessary (in this scenario it's NOT) and with great care.

Good luck!
alan dunne
Greenhorn

Joined: Jan 05, 2012
Posts: 6
Thanks for the help Roel and Himai.

I think I've got it working. After I call the constructor of my RoomDataController class (from my Data.getInstance(dbLocation) method) I then pass the Data instance to the RoomDataController. I then wait() on this instance in the lock() and call notify() on this instance in the unlock().

Does this sound ok to you? Also, have you any thoughts on the way I have set up my overall design?

Thanks again, Alan.
Roel De Nijs
Bartender

Joined: Jul 19, 2004
Posts: 5599
    
  15

Maybe you should have a look at the difference between notify and notifyAll...
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Singleton Data class - locking on the locked records map