In general, when you say "multithreading" you are implying "synchroniation", therefore your desire of not using synchronized
keyword sounds strange to me. Now to your question...
If I understood correctly, you want to share some state (which is stored in "object model") between different threads, but without using synchronized
keyword. Furthermore, your mention of I do not want to pass object reference to observers (object is mutable)
hints that observers should not be able to modify the state of the object.
If the above description is correct, then you could copy your "object model" in "observable thread" and pass it to callbacks in "observer thread". Something along these lines (not tested):
private void notifyListeners() {
for (int i=0; i<mListeners.size(); i++) {
final ObjectModel copyModel = new ObjectModel(mModel); // Assuming copy-constructor exists
mHandlers.get(i).post(new Runnable{
mListeners.get(i).notify(copyModel);
});
}
}
Please note that there are drawbacks to this approach:
- Once copy-constructed, the objects passed to your listeners no longer "track" the state of the observable. This means that your listeners could be working on outdated data.
- You copy your "object model" for each listener on each invocation of
notifyListeners
method. This might become a major overhead (depending on the size of the model, the amount of listeners and the rate of notifications)
- If you will want your listeners to be able to modify the model in the future, you'll need to change your code completely.
Due to above reasons, I would advice against usage of the above approach, except for the simplest cases. In other cases, I would pass the original object to listeners and ensure thread safety. Few notes that can help you:
- In order to prevent listeners from modifying the model, you could employ Interface Segregation Principle. The general idea: define two separate interfaces - one for reading the state of the model, and the other one for altering this state (e.g.
WritableModel
and ReadableModel
). Make your "object model" implement both, and then pass this model to listeners as ReadableModel
. This way you'll expose the listeners only to the non-mutating API of your model.
- Since there is only one thread that can alter the state of the model, you could make use of
volatile
members instead of full synchronization schemes. This will reduce the need for synchronized
blocks. Please keep in mind that while volatile
keyword resolves visibility issues, it does not address atomicity problems (i.e. you'll still need to use synchronized
for members of the model which are not written atomically).
- Instead of synchronizing the non-atomically written members yourself, you could make use of the classes found in
java.util.concurrent.atomic
package.