A few weeks ago I had a discussion with another developer about sharing entities (mapped by Hibernate) between threads. My personal opinion is that concurrency control should be localized to a few special objects (something we agreed upon). And most other objects don’t need any form of concurrency because one of the following rules applies:
- they are ‘immutable’. Safely created immutable objects are thread safe, eg a stateless service like a FireEmployeeService.
- they are confined to a single thread.
Entities are not immutable (in most cases), so the first rule doesn’t apply. Luckily the second rule applies in most standard applications: entities are created and used by a single thread (the concurrency control task has shifted to the database).
But as soon as an entity is transferred from one thread to another, the second rule doesn’t apply anymore, and you have to deal with concurrency control. This even applies to entities that are completely moved to another thread and not used by the original thread anymore!
So what can go wrong?
The most obvious thing that can go wrong is that the same object is used by multiple threads (the thread that created the object and the thread that received it). If this happens you can get all kinds of race problems.
Another thing that can go wrong are session related problems. If an entity has unloaded lazy loaded fields, it could happen that multiple threads are accessing the same Hibernate session.
object1@session1 transfered to thread-a
object2@session1 transfered to thread-b
If object1 and object2 both have a lazy loaded field, it could happen that thread-a and thread-b both are using the same session to load those fields. This is a bad thing because the Hibernate sessions are not thread safe. The safest thing you can do is evict the entity from the session before passing it to the other thread, so all references to the session are removed. It is up to the receiving thread, to decide if the object needs to be reattached.
The last thing that comes to mind are visibility problems: values written by one thread don’t have to be visible in other threads. Entities normally don’t have synchronized methods or volatile properties, so a different mechanism needs to be used to prevent visibility problems. Luckely with the new memory model, it is now perfectly clear which alternatives are available. A structure that posses the save handoff property (like a BlockingQueue) can be used to safely pass objects with visibility problems from one thread to another. It is important to realize that not just the entities could have visibility problems, the same problems can occur within the hibernate session. The session is not meant to be used by multiple threads, and therefor it has no reason to prevent visibility problems.
My advice is that sharing objects between threads should not be thought of lightly; you really needs to know what you are doing. This is even more true for Hibernate entities because there is a lot going on behind the screens.