简体   繁体   English

Java RMI和同步方法

[英]Java RMI and synchronized methods

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 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). 我认为在远程对象实现上使用synchronized方法 (因此在服务器上运行的实际实现)即使对该方法的调用来自不同的客户端机器(通过代理调用该方法),也会阻止该方法的并发执行......又名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和线程同步问题

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. 假设客户端A调用远程对象的同步方法。 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有直接访问权限。 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. 正如我们在Chap中讨论的那样。 6, distributed synchronization can be fairly complex. 6,分布式同步可能相当复杂。

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. 正如我们在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. 8,我们可能需要相对复杂的协议来处理这种情况,这可能会显着影响远程方法调用的整体性能。

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)。 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. 只有在实际执行分布式应用程序时,才能观察到应该在设计时处理的意外行为。 [...] [...]

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, 1996 between parenthesis. 我认为文章“Java系统的分布式对象模型”( 可在此处获得 )在文本中引用了Wollrath et all, 1996在括号之间。 However the only relevant paragraph I've found on that paper is this one: 然而,我在该论文中找到的唯一相关段落就是这一段:

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. 由于本地和远程对象的故障模式不同,分布式等待和通知要求所涉及的实体之间的协议更复杂(例如,客户端崩溃不会导致远程对象永久锁定),因此,不能轻易地适应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. 因此,客户端可以在远程引用上使用notify和wait方法,但该客户端必须知道此类操作不涉及实际的远程对象,只涉及远程对象的本地代理(存根)。

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时同步方法“不是那么同步”?

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. 您的第一个参考是,在单个VM实例中,RMI Stub(客户端到RMI服务器)上的调用将在内部同步。 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). 但是,它澄清了两个具有远程服务器存根的虚拟机不会被阻止同时调用远程服务器(这很明显,因为它们不能共享锁,而且RMI本身不会阻止服务器的并发)。 If this is undesirable, the RMI server will have to implement a locking mechanism to prevent multiple concurrent invocations. 如果这是不合需要的,则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中的线程进行并发访问。

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. 据我所知,每次调用RMI服务器都会在服务器端创建一个新线程(由我的2000日志文件见证)。 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. 如果这并不令人满意,我很抱歉。

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 objects like the ReentrantLock were introduced which are now the preferred way of doing things. 您还应该知道Java多线程自1996年以来发生了重大变化。作为原始语言设计一部分的notify()和wait()方法从并发专家和Java 5中得到了很多抨击(2004年,维基说引入了像ReentrantLock这样的高级并发对象 ,这些对象现在是首选的做事方式。

So the criticisms you mention are probably correct, but outdated. 所以你提到的批评可能是正确的,但已经过时了。

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. RMI存根是线程安全的,可以由单个客户端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. 我不知道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). 我认为在远程对象实现上使用synchronized方法(因此在服务器上运行的实际实现)即使对该方法的调用来自不同的客户端机器(通过代理调用该方法),也会阻止该方法的并发执行......又名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 prevent synchronization 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 synchronized does 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 synchronized method is synchronized. synchronized方法是synchronized. You can't disallow it. 你不能不允许它。

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. 正如我们在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. 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. 无论如何,RMI的设计者没有做出这样的选择。 There was no such choice to make. 没有这样的选择。 synchronized is synchronized whatever the RMI designers may or may not have wished, and similarly notify() and wait() are final. 无论RMI设计者可能想要什么,也可能不想要synchronized都是synchronized的,类似的notify()wait()也是final. They weren't free to make any choice. 他们无法做出任何选择。 The quotation you provided isn't a 'choice': it is merely a statement about the semantics of Java. 您提供的引用不是“选择”:它仅仅是关于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 obviously wrong. 我认为你正确地阅读它,它完全是完全错误的,不仅错误而且显然是错误的。 How could it possibly be right? 怎么可能是对的? Java RMI doesn't, and indeed cannot, alter or remove or extend the semantics of synchronized in any way. Java RMI不会, 实际上也不能以任何方式更改,删除或扩展synchronized的语义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM