6

我实际上有两个关于 Java RMI 和线程同步的问题:

1) 如果我将我的 RMI 远程方法实现为同步的,它们是否保证是互斥的?我需要确保没有两个 RMI 方法(提供给客户的方法)同时执行。

2)我有一个服务器定期执行的方法。它用于进行清理。当远程客户端正在运行/使用任何 RMI 方法时,我必须确保不会执行此特定方法。此外,当该方法运行时,RMI 调用应该是不可能的。即客户必须等待。知道我该怎么做吗?我读过关于锁的文章,但我不知道如何在这种情况下使用它们。

我考虑过将 RMI 方法实现为静态方法,并在 RMI 接口中包含该清理方法,但这似乎不是解决问题的优雅方法。

我还在 RMI 接口中编写了同步的清理方法。当我运行它进行测试时,方法之间似乎没有冲突,但我不能确定。

感谢您的时间和回答。

4

4 回答 4

11

1) 如果我将我的 RMI 远程方法实现为同步的,它们是否保证是互斥的?我需要确保没有两个 RMI 方法(提供给客户的方法)同时执行。

RMI 本身不提供这样的保证(与 EJB 不同),并且对同一个远程对象的两个调用可能会同时执行,除非您实现了一些同步。您的方法是正确的,并且同步所有方法确实可以确保它们中的任何一个都不会同时在同一个对象上运行。注意:synchronized单独的关键字等同于synchronized( this ).

2)我有一个服务器定期执行的方法。它用于进行清理。当远程客户端正在运行/使用任何 RMI 方法时,我必须确保不会执行此特定方法。

如果清理作业在另一个类中,您将需要定义一个锁,您将在远程对象和清理作业之间共享该锁。在远程对象中,定义一个将用作锁的实例变量。

protected Object lock = new Object();

按照惯例,人们Object为此目的使用一个。synchronized( remoteObj.lock ) { ... }然后,假设它在同一个包中,您需要使用 来锁定您的定期工作。

远程对象中的其他方法将需要以相同的方式同步(synchronized单独是不够的),以便远程方法调用和定期作业都是互斥的。

我考虑过将 RMI 方法实现为静态方法,并在 RMI 接口中包含该清理方法,但这似乎不是解决问题的优雅方法。

我还在 RMI 接口中编写了同步的清理方法。当我运行它进行测试时,方法之间似乎没有冲突,但我不能确定。

如果我理解得很好,您想让清理逻辑成为静态方法吗?synchronized一个单独的静态方法获取类的锁。“常规”方法synchronized在对象实例上获取锁。这些不是相同的隐式锁!

但是,如果您只实例化了一个远程对象,则可以将设为静态(这与锁定类相同,但更简洁一些)。然后,清理代码也可以是静态的,并且与远程对象是否在同一个类中。

骨骼:

public class MyRemoteClass {
   public static Object lock = new Object();

   public void doStuff()
   {
       synchronized( lock ) { ... }
   }
}

public class Cleanup {
   public static void doIt()
   {
       synchronized( MyRemoteClass.lock ) { ... }
   }
}
于 2010-02-16T20:13:24.327 回答
2
  1. 对于来自 RMI 客户端的每个调用,RMI 服务器将在一个新线程中执行该调用。您只需要同步对共享对象的访问。

  2. 另一个线程或计时器不会阻止您的服务器接受来自客户端的调用。这需要同步,最佳实践取决于清理作业运行多长时间可以中断,或者是否可以将请求放入队列等。最简单的方法是让 RMI 方法已经等待锁定由 ewernli 描述。

编辑:根据您的评论,展示如何实现这种基本同步的骨架。由于现在一切都是相互排斥的,因此您不能期望涉及多个客户的高性能。无论如何,这将满足您的要求。(我希望)。如果您的项目增长,您应该阅读并发教程

Object mutex = new Object();

int rmiMethod1() {
    synchronized (mutex) {
        doWhatNeeded1();
    }
}

int rmiMethod2() {
    synchronized (mutex) {
        doWhatNeeded2();
    }
}

// in your cleanup thread
void run() {
    synchronized (mutex) {
        cleanUp();
    }
}
于 2010-02-16T20:44:44.170 回答
0

为了澄清所有这些困惑:

  1. 如果您同步远程方法实现,一次只能执行一个客户端。

  2. 如果您在它加入的远程对象上同步您的清理任务 (1)。

  3. 您不能将远程方法定义为静态的。

于 2011-05-16T01:07:48.553 回答
-1

您必须记住,RMI 创建了“远程对象”的假象,但实际上至少有三个对象:本地存根、远程骨架和实际的远程对象。作为设计权衡,这种错觉并不完整,并且锁定本地存根。整个网络没有同步。在互联网上搜索 RMI+stub+synchronized,你会发现很多解释,比如这个:

Java RMI 和同步方法

因此,您需要自己实现某种非 RMI,纯粹的服务器端同步。然后你可以从你的远程方法调用这个纯服务器端锁;但是您需要额外的间接级别。

要测试您的代码,最简单的方法是在 Eclipse 等良好的调试器下暂停您的线程。Eclipse 会清楚地向您显示哪个暂停的线程持有哪个锁阻塞了其他线程。

于 2010-11-13T11:29:42.667 回答