Not it's time for me to walk the path of the SCJD.
I have been reading up a lot, and I have seen that very many have chosen implemented the Data access class (implementing Sun's interface) as a singleton object (to ensure that only one instance of the file handling code exists). At the same time, I have seen that is a common solution to synchronize all the data access methods (methods in the singleton Data).
A synchronized method is the same as a method with an internal synchronized(this) block, and that means that all executing threads will gain mutual exclusion based on the Data access object....which is a singleton object.
Doesn't this mean that if any thread is in the synchronized method A (in Data) then no other thread can enter any other synchronized method in Data, since they are locking on the same object? So regardless of they being in different synchronized blocks, they will still block each other?
What I'm getting at is this:
How could it be possible with a Data class being singleton and having all methods synchronized to be accessed in the following way?:
Thread 1 runs dataref.lock(1);
Thread 2 runs dataref.lock(2); // will cause T 2 to wait(), and will stay in a synchronized data method until notified.
Thread 1 runs dataref.update(1, obj); // Thread 1 will now be blocked because T 2 has aquired a thread lock of the same data object?
I'm one of those guys that took the singleton combined with the synchronized methods approach. I followed this approach because your code becomes very easy and a junior developer will understand it without any problem. On the other hand it is of course not that performant as it could be (but that's not really a major requirement).
Making your methods has the following effect:
it is not possible for two invocations of synchronized methods on the same object to interleave. When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.
You can read more about it in Sun's Concurrency Tutorial which can be found here. Just click here to go directly to the part about synchronized methods.
So it works as I suspected, as one thread enters a synchronized method no other thread can enter any synchronized methods locked on the same object.
Then that is why I wonder how it can be possible with this impl without getting a deadlock?
Thread a aquires the lock for record 1 (the lockrecord method is synchronized on the Data object)
thread b tries to aquire the lock for record 1, but it bubbles down to the lockmanager's wait() call. Now thread b is waiting for record 1 to be unlocked, and is actually waiting within the synchronized Data method lockrecord.
Now thread a cannot enter updaterecord(1) because this method is synchronized on data.. Deadlock.
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. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
So thread b entering wait() will release the lock on the data object, so thread a now can reaquire the lock and will be able to call update(). So there is no deadlock.
The idea behind a singleton Data object is that there is no point in having more Data objects as long as you have just one database file to access.