I would like to confirm my threading model with you. I have the DBAccess assignment with lock/unlock, update/delete, add, read and find interface. update and delete require lock and unlock..
1) In my Data.java class that implements the DBAccess interface I used one ReentrantReadWriteLock object as a static class member.
2) The update/delete/add methods serialize on the writeLock, they use a try, finally statement, the write unlock is done in the finally statement.
3) The read/find and other methods like readAllRecords serialize on the readLock, the read functions also use a try/finally statement.
4) The lock is only used when shared data is accessed, I considered the record count also as shared data, I tried to keep the lock as short as possible, validation code that accesses input parameters is done before the lock is acquired to keep the lock time as short as possible.
5) My Data class uses one instance of my LockManager class which contains a Map<Long,Long> (holds the record ID and lock cookie values). This class uses one static ReentrantLock and one Condition. Threads wait and wake up on the condition.
6) At any time only one lock is aquired. ReadWriteLock and the Lock in the lockManager are never both acquired.
7) When a thread blocks on a record it calls Condition.awaitUninterruptibly()
To stop/terminate my server while many clients are connected to it I used this solution:
1) In the Data class I have a boolean variable called serverIsRunning which is true by default. All DBAccess methods throw an IllegalStateException after they acquire the read/write lock if this class variable is false.
2) In the Lock manager class I have a similar boolean member variable called serverIsRunning which is true by default. All threads that wake up or acquire the LockManager.Lock throw an IllegalStateException if this variable is false.
3) In the Data class i have method called stopServer() that acquires the writeLock of the class just like update and delete.
4) When the user terminates the server in the UI the Data.stopServer() method is called, it acquires the writeLock and sets the Data.serverIsRunning to false. It also calls a method in the LockManager that similarly sets the LockManager.serverIsRunning to false and wakes up all threads.
5) After the stopServer method releases the write lock all waiting threads throw IllegalStateException, this error is caught in the client UI and the user is informed that the server was stopped.
1) Is this threading model enough for the exam?
2) Is something missing?
3) I implemented only one version of the Data class that is thread safe, this class is used in stand alone mode too which actually does not required thread safety, is this OK, I documented this issue in my choices.txt file.
1/ Any solution which makes the Data class thread-safe and is according to the specs (must requirements) will be enough for the exam. If you want to validate your solution, you can run Roberto's Data Class Test (see ScjdFaq for more info)
2/ The must requirements for the Data class with regard to locking and thread-safe are very straightforward: make your Data class thread-safe and when a record wants to lock an already locked record it has to give up CPU (it has to go in the waiting state).
3/ I also have just 1 Data class which is used in standalone mode too