Java 在存根上调用函数时 RMI 冻结

Java RMI freezes while calling a function on a stub

总结

我正在做一个项目,发现了这个问题:

我们在代码中发现了一个我们无法解决的问题。 首先我们给出一些关于 Eclipse 项目的一般信息以及如何执行它,然后我们给出一些关于代码的细节,最后我们描述问题。

项目

我们在 Eclipse 中构建了一个 Java Maven 项目。它包含两个源文件夹:src/main/java 和 src/test/java。主文件夹包含 Gallager、Humblet 和 Spira 算法的实现。目前我们有一个测试 SimpleTest 来查看算法的基本功能是否按预期工作。 代码可以这样执行:

  1. 解压附件DA-Lab3.zip.
  2. 在文件夹 DA-Lab3/target/classes.
  3. 中打开一个 command/terminal window
  4. 在此目录中启动 Java RMI 注册表([=91= 中的“rmiregistry &”],Windows 中的“start rmiregistry”)。
  5. 转到 command/terminal window 中的文件夹 DA-Lab3。
  6. 执行:“mvn clean install -f”。 (如果这不起作用,因为 Maven 无法清理文件夹,请尝试不带“清理”的相同命令。) 现在测试文件应该由 Java / Maven 执行。

密码

代码分为几个部分。需要理解的最重要的部分是 Node、Process 和 RMINetwork。 Node 包含实际的算法,Process 扩展 Node 具有创建边缘、实现发送方法和删除边缘等实用功能。 RMINetwork 处理与 RMI 相关的功能,如在注册表中注册进程、注销进程以及在 RMINetwork 中查找其他进程。

节点放在GHS.graph包中。该软件包还包含 Edge、NodeState 和 EdgeState。 消息由接收函数处理(第 221 行)。每种类型的消息都实现了接口 GHS.messages.IMessage 与函数 process 。 Node 中的接收函数在每条消息中调用这个处理函数。从消息中的这些过程函数调用 Node 中的特定函数。 Node中的这些函数根据算法处理消息。

进程放在包 GHS 中。它使用 id 变量和函数 send、connect、disconnect、id()、运行 和 stop 扩展了 Node。 send 函数确定接收者的 id,并给 RMINetwork 发送消息给接收者的任务。 Process class 还实现了 IProcess 接口。此接口由 RMI 客户端使用。

RMINetwork 放在通信包中。 class 包含注册、注销、查找和发送的功能。

问题

在 SimpleTest test1 中创建了三个进程和一个边缘。进程 0 连接到进程 2。然后进程 0 醒来并向进程 2 发送连接消息。进程 2 醒来并将连接消息发送回进程 0。然后进程 0 向进程 2 发送启动消息。但是在这里,Java 似乎没有抛出任何错误就冻结了。

进入细节: Java 似乎停留在:((IProcess) this.lookup(id)).receive(edge, message); RMINetwork r: 52.

为了查看实际问题是什么,我们向该函数添加了一些测试代码。 在第 49 行,我们添加了:IProcess p = (IProcess) this.lookup(id); 第 50 行:String s = p.id(); 第 51 行:System.out.println("networking"); 启用此测试代码后 Java 卡在第 50 行。

当第 50 行被禁用时,第 51 行被执行并且 Java 卡在第 52 行。

Process中实现了p.id()函数。第一条语句向命令行打印一个字符串。在Java卡住的那一刻,这条打印语句没有执行。

当我们将第 49 行替换为 49 时,我们添加了:IProcess p = (IProcess) this.lookup(edge.neighbour(id));(发件人现在实际上正在查找自己的 ID),然后在发送第二条而不是第三条消息时出现问题。

因此 Java RMI 似乎在调用存根时冻结。但它始终适用于第一条消息,并且根据第 49 行,它适用于第二条消息。因为没有抛出错误,所以我们不知道为什么 RMI 在此时冻结。

@Override
public void send(String id, Edge edge, IMessage message) throws Exception {
    System.out.println("testing");
    IProcess p = (IProcess) this.lookup(id);
    String s = p.id();
    //System.out.println(((IProcess) this.lookup(id)).id());
    System.out.println("networking");
    ((IProcess) this.lookup(id)).receive(edge, message);
    System.out.println("id found");
}

我们希望您能帮助我们。

您可以查看所有代码:https://github.com/mboom/DA-Lab3

您调用的远程方法没有返回。

事实证明,进程在一个线程中相互等待。向其他进程发送消息的旧启动方法在另一个进程通过存根调用方法时尚未完成。只要旧方法运行,这些方法就不会启动。因为旧方法正在等待响应(只有当这些旧方法完成时才会出现),系统最终陷入死锁。我们通过在新线程中执行节点的 receive 方法解决了这个问题。