Java RMI 和同步方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3507253/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 02:09:24  来源:igfitidea点击:

Java RMI and synchronized methods

javaconcurrencysynchronizationrmi

提问by Andrea Zilio

I'm studying the book "Distributed Systems" (by Tanenbaum & Van Steen) and they say something that seems to conflict to what seems to be instead thought by many on Java RMI and synchronized methods.

我正在研究“分布式系统”一书(由 Tanenbaum 和 Van Steen 撰写),他们所说的似乎与许多人对 Java RMI 和同步方法的看法相矛盾。

What I thought is that using a synchronized methodon a Remote Object implementation (so the real implementation running at the server) concurrent execution of that method is prevented even when the calls to that method are from different clients machines (calling the method via a Proxy... aka a Stub).

我的想法是,在远程对象实现上使用同步方法(因此在服务器上运行的真正实现)阻止了该方法的并发执行,即使对该方法的调用来自不同的客户端机器(通过代理调用该方法) ...又名存根)。

I've seen that a lot of people have the same opinion, look here for example: Java RMI and Thread Synchronization questions

我看到很多人都有相同的看法,例如看这里:Java RMI and Thread Synchronization questions

In the book it's instead said that concurrent execution of synchronized methods is not prevented when using RMI.

在这本书中,反而说在使用 RMI 时不会阻止同步方法的并发执行。

Here's the relevant excerpt from the book (you can read the bold sentence only, but you can read the context if you prefer to):

这是本书的相关摘录(您只能阅读粗体句子,但如果您愿意,也可以阅读上下文):

Logically, blocking in a remote object is simple. Suppose that client A calls a synchronized method of a remote object. To make access to remote objects look always exactly the same as to local objects, it would be necessary to block A in the client-side stub that implements the object's interface and to which A has direct access. Likewise, another client on a different machine would need to be blocked locally as well before its request can be sent to the server. The consequence is that we need to synchronize different clients at different machines. As we discussed in Chap. 6, distributed synchronization can be fairly complex.

An alternative approach would be to allow blocking only at the server. In principle, this works fine, but problems arise when a client crashes while its invocation is being handled by the server. As we discussed in Chap. 8, we may require relatively sophisticated protocols to handle this situation, and which that may significantly affect the overall performance of remote method invocations.

Therefore, the designers of Java RMI have chosen to restrict blocking on remote objects only to the proxies (Wollrath et al., 1996). This means that threads in the same process will be prevented from concurrently accessing the same remote object, but threads in different processes will not.Obviously, these synchronization semantics are tricky: at the syntactic level (ie, when reading source code) we may see a nice, clean design. Only when the distributed application is actually executed, unanticipated behavior may be observed that should have been dealt with at design time. [...]

从逻辑上讲,阻塞远程对象很简单。假设客户端 A 调用远程对象的同步方法。为了使对远程对象的访问与对本地对象的访问始终完全相同,有必要在实现对象接口且 A 可以直接访问的客户端存根中阻塞 A。同样,另一台机器上的另一个客户端也需要在本地被阻止,然后才能将其请求发送到服务器。结果是我们需要在不同的机器上同步不同的客户端。正如我们在第 1 章中讨论的那样。6、分布式同步可能相当复杂。

另一种方法是只允许在服务器上进行阻塞。原则上,这工作正常,但是当客户端在服务器处理其调用时崩溃时会出现问题。正如我们在第 1 章中讨论的那样。8,我们可能需要相对复杂的协议来处理这种情况,这可能会显着影响远程方法调用的整体性能。

因此,Java RMI 的设计者选择将远程对象的阻塞仅限于代理(Wollrath 等,1996)。这意味着将阻止同一进程中的线程并发访问同一个远程对象,但不同进程中的线程不会。显然,这些同步语义是棘手的:在句法级别(即,在阅读源代码时),我们可能会看到一个漂亮、干净的设计。只有在实际执行分布式应用程序时,才会观察到本应在设计时处理的意外行为。[...]

I think that the paper "A Distributed Object Model for the Java System" (available here) is referenced in the text by the note Wollrath et all, 1996between parenthesis. However the only relevant paragraph I've found on that paper is this one:

我认为论文“Java 系统的分布式对象模型”(可在此处获得)在文中通过Wollrath et all, 1996括号之间的注释引用。然而,我在那篇论文上找到的唯一相关段落是这个:

Due to the differing failure modes of local and remote objects, distributed wait and notification requires a more sophisticated protocol between the entities involved (so that, for example, a client crash does not cause a remote object to be locked forever), and as such, cannot be easily fitted into the local threading model in Java. Hence, a client can use notify and wait methods on a remote reference, but that client must be aware that such actions will not involve the actual remote object, only the local proxy (stub) for the remote object.

由于本地和远程对象的故障模式不同,分布式等待和通知需要在所涉及的实体之间使用更复杂的协议(这样,例如,客户端崩溃不会导致远程对象永远被锁定),因此, 不能很容易地适应 Java 中的本地线程模型。因此,客户端可以在远程引用上使用通知和等待方法,但该客户端必须意识到此类操作不会涉及实际的远程对象,只涉及远程对象的本地代理(存根)。

Am I interpreting the text in the wrong way or is in fact stated that synchronized methods are "not so synchronized" when using RMI?

我是否以错误的方式解释了文本,或者实际上说使用 RMI 时同步方法“不那么同步”?

回答by mwhidden

What your first reference is saying is that within a single VM instance, invocations on an RMI Stub (client to an RMI server) will be internally synchronized. That is, the stub (or proxy, as the text seems to call it) itself will prevent multiple threads from concurrently invoking a method on the remote server. It clarifies, however, that two VMs each with stubs for a remote server will not be blocked from concurrently invoking the remote server (which is obvious, because they cannot share a lock, and RMI itself does not prevent concurrency at the server). If this is undesirable, the RMI server will have to implement a locking mechanism to prevent multiple concurrent invocations.

您的第一个参考是说在单个 VM 实例中,对 RMI Stub(客户端到 RMI 服务器)的调用将在内部同步。也就是说,存根(或代理,如文中所称)本身将阻止多个线程同时调用远程服务器上的方法。然而,它澄清了两个分别具有远程服务器存根的 VM 不会被阻止同时调用远程服务器(这是显而易见的,因为它们不能共享锁,并且 RMI 本身不会阻止服务器上的并发)。如果这是不可取的,RMI 服务器将必须实现锁定机制以防止多个并发调用。

The second reference does not in anyway contradict the first. The second merely clarifies that if you try to synchronize on a stub, it will only be locked locally, and will not impact the concurrency of the remote server.

第二个参考与第一个没有任何矛盾。第二个只是说明如果你尝试在存根上同步,它只会在本地被锁定,不会影响远程服务器的并发。

Combining the two texts, we can read that synchronizing on a stub will prevent the multiple threads in the same VM from concurrently accessing the remote, but will not prevent threads in distinct VMs from concurrent access.

结合这两个文本,我们可以看出,在存根上进行同步将阻止同一 VM 中的多个线程并发访问远程,但不会阻止不同 VM 中的线程并发访问。

回答by user207421

You are correct. The text is wrong. RMI stubs are thread-safe and can be invoked simultaneously by multiple threads within a single client JVM. I'm not aware of any statement or text by Wollrath et all that says anything different, and I've been following this topic since 1997.

你是对的。文字有误。RMI 存根是线程安全的,可以由单个客户端 JVM 中的多个线程同时调用。我不知道 Wollrath 等人的任何声明或文字有什么不同的说法,而且我自 1997 年以来一直在关注这个话题。

Specifically:

具体来说:

What I thought is that using a synchronized method on a Remote Object implementation (so the real implementation running at the server) concurrent execution of that method is prevented even when the calls to that method are from different clients machines (calling the method via a Proxy... aka a Stub).

我的想法是,在远程对象实现上使用同步方法(因此在服务器上运行的真正实现)阻止了该方法的并发执行,即使对该方法的调用来自不同的客户端机器(通过代理调用该方法) ...又名存根)。

You are correct.

你是对的。

In the book it's instead said that concurrent execution of synchronized methods is not prevented when using RMI.

在这本书中,反而说在使用 RMI 时不会阻止同步方法的并发执行。

The book is not only wrong, it is stating an impossibility. How exactly could RMI preventsynchronization from working?

这本书不仅是错误的,而且还陈述了一种不可能的情况。RMI 究竟如何阻止同步工作?

Logically, blocking in a remote object is simple. Suppose that client A calls a synchronized method of a remote object.

从逻辑上讲,阻塞远程对象很简单。假设客户端 A 调用远程对象的同步方法。

Then blocking occurs at the server, by the normal operation of Java.

然后在服务器上发生阻塞,通过 Java 的正常运行。

To make access to remote objects look always exactly the same as to local objects, it would be necessary to block A in the client-side stub that implements the object's interface and to which A has direct access.

为了使对远程对象的访问与对本地对象的访问始终完全相同,有必要在实现对象接口且 A 可以直接访问的客户端存根中阻塞 A。

Rubbish. The fact that the remote method implementation is synchronizeddoes everything that is necessary.

垃圾。远程方法实现的事实synchronized完成了所有必要的工作。

Likewise, another client on a different machine would need to be blocked locally as well before its request can be sent to the server.

同样,另一台机器上的另一个客户端也需要在本地被阻止,然后才能将其请求发送到服务器。

Again this is rubbish.

这又是垃圾。

The consequence is that we need to synchronize different clients at different machines.

结果是我们需要在不同的机器上同步不同的客户端。

Rubbish again.

又是垃圾。

An alternative approach would be to allow blocking only at the server.

另一种方法是只允许在服务器上进行阻塞。

'Allow'? What does this mean? A synchronizedmethod is synchronized.You can't disallowit.

'允许'?这是什么意思?一种synchronized方法是synchronized.你不能禁止它。

In principle, this works fine, but problems arise when a client crashes while its invocation is being handled by the server.

原则上,这工作正常,但是当客户端在服务器处理其调用时崩溃时会出现问题。

Again rubbish. No such problems arise. The server recovers from this situation either via a read timeout or an write exception or even successful completion of the remote method. In all three cases, the method exits, the synchronization lock is released, and life continues.

又是垃圾。不会出现这样的问题。服务器通过读取超时或写入异常甚至远程方法的成功完成从这种情况中恢复。在这三种情况下,方法退出,同步锁被释放,生命继续。

As we discussed in Chap. 8, we may require relatively sophisticated protocols to handle this situation, and which that may significantly affect the overall performance of remote method invocations.

正如我们在第 1 章中讨论的那样。8,我们可能需要相对复杂的协议来处理这种情况,这可能会显着影响远程方法调用的整体性能。

Nonsense.

废话。

Therefore, the designers of Java RMI have chosen to restrict blocking on remote objects only to the proxies (Wollrath et al., 1996).

因此,Java RMI 的设计者选择将远程对象的阻塞仅限于代理(Wollrath 等,1996)。

I am not aware what else this could refer to other than the excerpt you quoted, and I've read that paper many times. If the authors want to rely on this paper they should have provided a quotation and a proper citation to chapter and verse.

除了您引用的摘录之外,我不知道这还可以指什么,而且我已经多次阅读该论文。如果作者想依赖这篇论文,他们应该提供引文和适当的章节引文。

In any case the designers of RMI made no such choice. There was no such choice to make. synchronizedis synchronizedwhatever the RMI designers may or may not have wished, and similarly notify()and wait()are final.They weren't free to makeany choice. The quotation you provided isn't a 'choice': it is merely a statement about the semantics of Java.

在任何情况下,RMI 的设计者都没有做出这样的选择。没有这样的选择。synchronizedsynchronized什么RMI的设计师可能会或可能不会有希望,同样notify()wait()final.他们不能自由做出任何选择。您提供的引用不是“选择”:它只是关于 Java 语义的声明。

Am I interpreting the text in the wrong way or is in fact stated that synchronized methods are "not so synchronized" when using RMI?

我是否以错误的方式解释了文本,或者实际上说使用 RMI 时同步方法“不那么同步”?

I think you're reading it correctly, and it's completely and utterly wrong, and not only wrong but obviouslywrong. How could it possibly be right? Java RMI doesn't, and indeed cannot,alter or remove or extend the semantics of synchronizedin any way.

我认为你读对了,它完全错误,不仅错误而且明显错误。怎么可能是对的?Java RMI 没有,也确实不能,synchronized以任何方式改变、删除或扩展 的语义。

回答by stacker

As far as I know each call to an RMI server will create a new thread (witnessed by my log files from 2000) on server side. If you do synchronizing at server side you should be safe. I faced some ancient warnings from literature as you posted. As an practicioner I prefered to run the software for a month or so and decided it was stable enough for for production. I'm Sorry if this isn't not satisfying.

据我所知,对 RMI 服务器的每次调用都会在服务器端创建一个新线程(由我 2000 年的日志文件见证)。如果您在服务器端进行同步,您应该是安全的。当您发布时,我遇到了一些来自文学的古老警告。作为一名从业者,我更喜欢将软件运行一个月左右,并认为它对于生产来说足够稳定。如果这不令人满意,我很抱歉。

回答by Michael Clerx

You should also be aware that Java multi-threading has changed significantly since 1996. The notify() and wait() methods that were part of the original language design got a lot of flack from concurrency experts and in Java 5 (2004, says wiki) high level concurrency objectslike the ReentrantLockwere introduced which are now the preferred way of doing things.

您还应该意识到 Java 多线程自 1996 年以来发生了重大变化。作为原始语言设计一部分的 notify() 和 wait() 方法受到了并发专家和 Java 5(2004,wiki 说)的大量抨击)引入了像ReentrantLock这样的高级并发对象,它们现在是首选的处理方式。

So the criticisms you mention are probably correct, but outdated.

所以你提到的批评可能是正确的,但已经过时了。