通常,当您说“多线程”时,您是在暗示“同步”,因此您不使用synchronized
关键字的愿望对我来说听起来很奇怪。现在回答你的问题...
如果我理解正确,您想在不同线程之间共享一些状态(存储在“对象模型”中),但不使用synchronized
关键字。此外,您提到I do not want to pass object reference to observers (object is mutable)
观察者不应修改对象状态的提示。
如果上面的描述是正确的,那么您可以将您的“对象模型”复制到“可观察线程”中并将其传递给“观察线程”中的回调。这些方面的东西(未经测试):
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);
});
}
}
请注意,这种方法有一些缺点:
- 复制构造后,传递给您的侦听器的对象不再“跟踪”可观察对象的状态。这意味着您的听众可能正在处理过时的数据。
notifyListeners
您在每次调用方法时为每个侦听器复制“对象模型” 。这可能会成为主要开销(取决于模型的大小、侦听器的数量和通知的速率)
- 如果您希望您的听众将来能够修改模型,您将需要完全更改您的代码。
由于上述原因,我建议不要使用上述方法,除了最简单的情况。在其他情况下,我会将原始对象传递给侦听器并确保线程安全。一些可以帮助您的注意事项:
- 为了防止监听器修改模型,您可以使用接口隔离原则。总体思路:定义两个独立的接口——一个用于读取模型的状态,另一个用于更改此状态(例如
WritableModel
和ReadableModel
)。让你的“对象模型”同时实现,然后将此模型作为ReadableModel
. 这样,您将只向模型的非变异 API 公开侦听器。
- 由于只有一个线程可以更改模型的状态,因此您可以使用
volatile
成员而不是完全同步方案。这将减少对synchronized
块的需求。请记住,虽然volatile
关键字解决了可见性问题,但它不能解决原子性问题(即,您仍然需要使用synchronized
非原子编写的模型成员)。
- 您可以使用 package.json 中的类,而不是自己同步非原子编写的成员
java.util.concurrent.atomic
。