Why does find() need to be synchronized? Here is my take.
First off, let me state I struggled with synchronization in the Data class quite a bit at the start and I wasn't clear on what to synchronize and what not to. There is lots of discussion about it but people don't seem to agree. The thing that cleared it up for me was reading "Effective Java" (Joshua Bloch). In there he states you should *always* synchronize access to shared, mutable data. He gives a very clear explanation why this is so. I won't go into the details. So that is my rule: If I'm reading or writing shared, mutable data I synchronize it.
Let's apply this to the find() method. Notice that method uses the recordCount field in a for loop. What would happen if the recordCount was changed after your loop did the comparison to recordCount, but before it processed that record? It would be ugly--you might return data that had been deleted, or read data that hadn't been fully written.
In the book, he goes on to explain that overly clever people try to increase concurrency by not synchronizing atomic operations. This is dangerous and wrong.
Finally he states that developers that fail to synchronize properly often have the program work fine in testing. Picture the situation I described above in the find method. It is unlikely to happen--even if you do tons of testing. When it does happen, you might not blow up in the find() method, you'll probably crash elsewhere, which will make the problem nearly impossible to debug. Also, recreating the error will be almost impossible. A true debugging nightmare.
I'm sure I haven't explained this as well as he did, but hopefully that made sense.
The book again is "Effective Java" by Bloch. Great book.