I don't synchronize at that level, the question to ask yourself is "what resource am I protecting from multiple accesses?". In my implementation only a single
thread accesses a Data instance at a time. That thread is the thread that is performing actions for the client over the network.
All the syncronization is in the lower level objects that represents the database file and the lock manager.
I syncronize on the RandomAccessFile instance to prevent problems where one thread moves the file pointer and another moves it elsewhere before it can read or write the data.
I also synchronize on the Map of locked resources and the Lock object that is waiting or being notified.
All this is carefully done to ensure that the order is always Map->Lock or Map->RandomAccessFile, never the other way around, so there is no danger of deadlock.