The question is: which part of code should be synchronized?
As always, you need to synchronize access to data, which is modified by one thread and simultaneous either modified or even just read by another thread.
In this example, that shared data is your id2foo Dictionary. So, put a lock around the following statements:
To maximize concurrency (i.e. to minimize lock contention) you should make the lifetime of these locks as short as possible: i.e. only around the few statements which I listed above, and not around the entire getFoo
and addFoo
methods.
Beware however that doing this with a cache might get you stale data; that can happen anyway with a database (depending on the 'transaction isolation level'), but beware.
If I'll synchronize all calls to the cache-collection then I'm not even sure that using cache would improve performance.
In my opinion it is likely to improve performance: assuming you're not storing too much data in the cache, it can take much less time to read from the cache than to read from the database, even if you need to wait for a lock on the cache, especially if the lock on the cache is short-lived as I've suggested it should be.
If you want to be fancy, you can use a multi-reader/single-writer lock, so that there's no contention when multiple threads are reading from the cache while no-one is writing to the cache.