我认为,在远程对象实现上使用同步方法(因此在服务器上运行的真正实现)即使调用该方法的客户端机器不同(通过代理调用该方法...也就是存根),也会防止对该方法的并发执行。
我发现很多人有同样的观点,例如在这里:Java RMI 和线程同步问题 但在书中却说,使用RMI时,同步方法的并发执行并未被阻止。
以下是书中相关摘录(您可以只阅读粗体句子,但如果您愿意,也可以阅读上下文):
逻辑上,在远程对象中进行阻塞是很简单的。假设客户端A调用了远程对象的同步方法。为了使对远程对象的访问看起来始终与对本地对象的访问完全相同,需要在实现对象接口的客户端存根中阻止A,并且A可以直接访问该存根。同样,在将请求发送到服务器之前,不同机器上的另一个客户端也需要在本地被阻塞。因此,我们需要在不同的机器上同步不同的客户端。正如我们在第6章中讨论的那样,分布式同步可能会相当复杂。 另一种方法是仅允许在服务器上进行阻塞。原则上,这样做没问题,但是当客户端在服务器处理其调用时崩溃时会出现问题。正如我们在第8章中讨论的那样,我们可能需要相对复杂的协议来处理这种情况,这可能会显着影响远程方法调用的总体性能。 因此,Java RMI的设计者选择仅限制对代理的远程对象进行阻塞(Wollrath等人,1996年)。这意味着在同一进程中的线程将无法同时访问相同的远程对象,但在不同进程中的线程则不会。显然,这些同步语义很棘手:在句法层面(即阅读源代码时)我们可能会看到一个漂亮、干净的设计。只有在实际执行分布式应用程序时,才会观察到可能应该在设计时处理的未预期行为。[...]
我认为文中的注释
Wollrath et all,1996
是指向论文"A Distributed Object Model for the Java System"(可在此处获得)。然而,我在那篇论文中找到的唯一相关段落是这个:
由于本地对象和远程对象存在不同的故障模式,分布式等待和通知需要在涉及实体之间使用更复杂的协议(例如,客户端崩溃不会导致远程对象永久锁定),因此不能轻松地适应Java中的本地线程模型。因此,客户端可以在远程引用上使用notify和wait方法,但该客户端必须意识到这样的操作不涉及实际的远程对象,只涉及远程对象的本地代理(存根)。
我是错误地解释了文本,还是实际上陈述了当使用RMI时同步方法“不太同步”?