我正在研究“分布式系统”一书(由Tanenbaum& Van Steen撰写),他们说的东西似乎与许多人在Java RMI和同步方法上的想法相冲突。
我认为在远程对象实现上使用 synchronized方法(因此在服务器上运行的实际实现)即使对该方法的调用来自不同的客户端机器(通过代理调用方法...又称Stub)。
我看过很多人都有同样的看法,例如:Java RMI and Thread Synchronization questions
在本书中,它表示使用RMI时不会阻止同步方法的并发执行。
以下是本书的相关摘录(您只能阅读粗体句子,但如果您愿意,可以阅读上下文):
逻辑上,阻止远程对象 很简单。假设客户端A呼叫 远程的同步方法 宾语。要访问远程 对象看起来总是完全一样 对于本地对象,它会 阻止A的必要条件 实现的客户端存根 对象的界面和A所具有的界面 直接访问。同样,另一个 客户在另一台机器上会 也需要在本地阻止 在它的请求可以发送到 服务器。结果就是我们 需要同步不同的客户端 在不同的机器上。正如我们讨论过的 在Chap。 6,分发 同步可能相当复杂。
另一种方法是 仅允许在服务器上阻止。在 原则,这很好,但是 客户端崩溃时会出现问题 正在处理它的调用 由服务器。我们在讨论中 第一章。 8,我们可能需要相对 处理这个问题的复杂协议 情况,以及可能的情况 显着影响整体 远程方法的表现 调用
因此,Java RMI的设计者 已选择限制阻止 远程对象只能代理 (Wollrath等,1996)。这意味着 那个线程在同一个进程中会 同时防止 访问同一个远程对象,但是 不同进程中的线程会 没有。显然,这些同步 语义是棘手的:在句法上 级别(即,阅读源代码时) 我们可能会看到一个漂亮,干净的设计。只要 当分布式应用程序是 实际执行,意外 可能会发现应该遵守的行为 已在设计时处理过。 [...]
我认为文章“Java系统的分布式对象模型”(available here)在文本中由括号Wollrath et all, 1996
引用。然而,我在该论文中找到的唯一相关段落就是这一段:
由于本地和远程的故障模式不同 对象,分布式等待和通知需要一个 涉及的实体之间更复杂的协议 (例如,客户端崩溃不会 导致远程对象永远被锁定),以及 这样,不能轻易装入局部穿线 Java中的模型。因此,客户端可以使用通知和等待 远程引用上的方法,但该客户端必须是 意识到这样的动作不会涉及实际的遥控器 对象,只有远程的本地代理(存根) 对象
我是否以错误的方式解释文本,或者实际上说使用RMI时同步方法“不是那么同步”?
答案 0 :(得分:12)
您的第一个参考是,在单个VM实例中,RMI Stub(客户端到RMI服务器)上的调用将在内部同步。也就是说,存根(或代理,如文本似乎称之为)本身将阻止多个线程同时调用远程服务器上的方法。但是,它澄清了两个具有远程服务器存根的虚拟机不会被阻止同时调用远程服务器(这很明显,因为它们不能共享锁,而且RMI本身不会阻止服务器的并发)。如果这是不合需要的,则RMI服务器必须实现锁定机制以防止多个并发调用。
第二个参考文献并不反对第一个参考文献。第二个只是澄清了如果你尝试在存根上进行同步,它只会在本地锁定,并且不会影响远程服务器的并发性。
结合这两个文本,我们可以看到在存根上同步将阻止同一个VM中的多个线程同时访问远程,但不会阻止不同VM中的线程进行并发访问。
答案 1 :(得分:1)
据我所知,每次调用RMI服务器都会在服务器端创建一个新线程(由我2000年的日志文件见证)。如果在服务器端进行同步,则应该是安全的。你发布的文章中我遇到了一些古老的警告。作为一个实践者,我更喜欢运行该软件一个月左右,并认为它足够稳定,可用于生产。如果这并不令人满意,我很抱歉。
答案 2 :(得分:1)
您还应该知道Java多线程自1996年以来发生了重大变化。作为原始语言设计一部分的notify()和wait()方法在并发专家和Java 5(2004年)中引起了很大的冲击。 ,wiki说high level concurrency objects就像引入了ReentrantLock一样,现在是首选的做事方式。
所以你提到的批评可能是正确的,但过时了。
答案 3 :(得分:0)
你是对的。文字错了。 RMI存根是线程安全的,可以由单个客户端JVM中的多个线程同时调用。我不知道Wollrath等所有发表过任何不同的声明或文字,自1997年以来我就一直关注这个话题。
具体做法是:
我认为在远程对象实现上使用synchronized方法(因此在服务器上运行的实际实现)即使对来自不同客户端计算机的调用(即调用该方法),也会阻止该方法的并发执行通过代理...也称为Stub)。
你是对的。
在本书中,它表示使用RMI时不会阻止同步方法的并发执行。
这本书不仅错误,而且说不可能。 RMI 如何阻止同步工作?
逻辑上,远程对象中的阻塞很简单。假设客户端A调用远程对象的同步方法。
然后通过Java的正常操作在服务器上发生阻塞。
要使对远程对象的访问看起来与本地对象完全相同,有必要在实现对象接口的客户端存根中阻止A,并且A可以直接访问。
垃圾。远程方法实现为synchronized
的事实可以完成所有必要的工作。
同样,在将其请求发送到服务器之前,还需要在本地阻止另一台计算机上的另一台客户端。
这又是垃圾。
结果是我们需要在不同的机器上同步不同的客户端。
再次垃圾。
另一种方法是仅允许在服务器上进行阻止。
'允许'?这是什么意思? synchronized
方法是synchronized.
您不能禁止。
原则上,这样可以正常工作,但是当客户端在服务器处理其调用时崩溃时会出现问题。
再次垃圾。没有出现这样的问题。服务器通过读取超时或写入异常甚至成功完成远程方法从这种情况中恢复。在所有这三种情况下,方法退出,同步锁定被释放,生命继续。
正如我们在Chap中所讨论的那样。 8,我们可能需要相对复杂的协议来处理这种情况,这可能会显着影响远程方法调用的整体性能。
无意义。
因此,Java RMI的设计者选择仅限制代理对远程对象的阻塞(Wollrath等,1996)。
我不知道除了你引用的摘录之外还有什么可以引用的,而且我已多次读过那篇论文。如果作者想要依赖这篇论文,他们应该为章节和诗节提供引文和适当的引用。
无论如何,RMI的设计者没有做出这样的选择。没有这样的选择。 synchronized
synchronized
无论RMI设计师可能会或可能不希望如此,notify()
和wait()
同样final.
他们无法自由做出任何选择。您提供的引用不是“选择”:它只是关于Java语义的声明。
我是否以错误的方式解释文本,或者实际上说使用RMI时同步方法“不是那么同步”?
我认为你正确地阅读它,它完全是完全错误的,而且不仅错误,而且显然错误。怎么可能是对的?
Java RMI不会, ,实际上不能, 以任何方式更改,删除或扩展synchronized
的语义。