Roel - here is the secret. I call lock and unlock inside the read method to lock the record, just around the critical section of code. You can use my read code without first locking and then unlocking. It is thread safe.
I use a static lock object (java.util.concurrent.locks.Lock) that is shared amongst all instances of the Data class. In my lock method I first have to get a lock on the static lock object. I then check a static HashMap to see if the record is locked. If it is I wait if not I continue, enter the recNo in the HashMap locking the record. I then unlock the static lock object so another thread can get in.
The create method is threadsafe because to execute create you first have to get a lock on the static lock object. Once this is achieved all other threads must wait. The create method is the only method that needs to be locked for the duration of execution.
As I said previously delete and update can be executed in a threadsafe manner without synchronizing these methods. The record has already been locked in the lock method. As I said before the secret to maximum concurrency is not to make Data a Singleton. Then each instance of Data has its own handle to the raf which means that different records in the database can be read, updated and deleted concurrently. Each thread has its own pointer to the raf. Remember, local variables are threadsafe. Static variables are used to coordinate the locking.