Java RMI and Thread Synchronization questions
Asked Answered
V

4

6

I actually have two questions about Java RMI and thread synchronization:

1) If I implement my RMI remote methods as synchronized, are they guaranteed to be mutually exclusive? I need to make sure that no two of my RMI methods (methods offered to clients) execute at the same time.

2) I have a method that the server executes periodically. It is used to do cleanups. I have to make sure that this particular method does not execute when there is any RMI method being run/used by remote clients. Also, when that method is running, RMI calls shouldn't be possible. I.e. Clients must wait. Any idea how I can do that? I have read about Locks, but I do not know how to use them in this scenario.

I have considered implementing RMI methods as static and including that cleanup method inside the RMI interface, but it does not seem to be an elegant way of solving the problem.

I have also written the cleanup method inside the RMI interface as synchronized. When I ran it for testing, there did not seem to be collisions between methods, but I cannot be sure.

Thank you for your time and answers.

Vaientina answered 16/2, 2010 at 19:55 Comment(1)
If anything posted by ewernli or me was helpful, give at least an upvote ;-)Gannet
M
11

1) If I implement my RMI remote methods as synchronized, are they guaranteed to be mutually exclusive? I need to make sure that no two of my RMI methods (methods offered to clients) execute at the same time.

RMI does not provide such guarantee on its own (unlike EJB) and two calls on the same remote object may be executed concurrently unless you implement some synchronization. Your approach is correct, and synchronizing all methods will indeed ensure that no two of them run at the same time on the same object. Note: The keyword synchronized alone is equivalent to synchronized( this ).

2) I have a method that the server executes periodically. It is used to do cleanups. I have to make sure that this particular method does not execute when there is any RMI method being run/used by remote clients.

If the cleanup job is in another class, you will need to define a lock that you will share between the remote object and the cleanup job. In the remote object, define an instance variable that you will use as a lock.

protected Object lock = new Object();

By convention, people use an Object for this purpose. Then you need to grab the lock in your periodic job with synchronized( remoteObj.lock ) { ... }, assuming it's in the same package.

The other methods in the remote object will need to be synchronized the same way (synchronized alone is not enough), so that remote method calls and periodic job are both exclusive.

I have considered implementing RMI methods as static and including that cleanup method inside the RMI interface, but it does not seem to be an elegant way of solving the problem.

I have also written the cleanup method inside the RMI interface as synchronized. When I ran it for testing, there did not seem to be collisions between methods, but I cannot be sure.

If I understand well, you would like to have the cleanup logic be a static method? A static method with synchronized alone grabs a lock on the class. A "regular" method with synchronized grabs a lock on the object instance. These are not the same implicit locks!

But if you have only one remote object instantiated, you can make the lock static (That's the same as locking on the class, but is a bit cleaner). The cleanup code can then be static as well and be in the same class as the remote object or not.

Skeleton:

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

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

public class Cleanup {
   public static void doIt()
   {
       synchronized( MyRemoteClass.lock ) { ... }
   }
}
Macaulay answered 16/2, 2010 at 20:13 Comment(9)
I don't know about the downvote. Anyway, can you please elaborate more on the locking mechanism? I see a reference in another reply, and I didn't understand all of it. If I implement the lock in a remote object, how can I acquire the lock from a Server local object? Something like a public static variable in the remote object? Or if you could provide any links/tutorials/code snippets, it'd be ok too. Thanks. :)Vaientina
'RMI does not provide such guarantee.' True but that wasn't the question. He is synchronizing. Synchronizing does provide that guarantee.Alanis
And synchronizing all the methods would work just as well as a lock object on the evidence we've been given.Alanis
That is what I need to confirm EJP. If I implement all the methods in the RMI interface as synchronized, can I be sure no two of them are going to run at the same time at any moment?Vaientina
@EJP Thanks for the explanation. I have edited my answer. Hope it is better now.Macaulay
@Inf.S: synchronizing the methods ensures that no two of them run at the same time on the same object. If it's enough will depend how you implement the cleanup logic: in a separate class or not, as a static method or not. I propose that you use a static lock.Macaulay
After reading your solution, I am considering implementing the cleanup code in the same class as the remote object, but not as static. The cleanup code won't be in the remote interface, so clients won't know about it. When I am instantiating the remote object for RMI, I can use that same variable to call the Cleanup code when I need. I believe this should be enough to ensure that my cleanup code and client-callable methods do not run at the same time. Your opinions on this?Vaientina
It's ok as well. Then synchronizing all methods with synchronized is enough.Macaulay
Take a look at this question: stackoverflow.com/questions/3507253 . If what I've written there is true than it may be a good reason for the downvotes. I really hope to have your opinion on that.Fusion
G
2
  1. For each call from a RMI client the RMI server will execute the call in a new thread. You only need to synchronize access to shared objects.

  2. Another thread or timer will not stop your server from accepting calls from the client side. This needs synchronization, the best practice depends on how long the cleanup job runs can it be interrupted, or would it be possible to put the requests in a queue etc. The easiest way would be to let the RMI methods wait for the lock as already described by ewernli.

EDIT: According to your comment, a skeleton that demonstrates how to achieve this kind of basic synchronization. Since everything is now mutually exclusive, you can't expect high performance with multiple clients involved. Anyway this would cover your requirements. (I hope). If your project grows you should read the Concurrency Tutorial

Object mutex = new Object();

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

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

// in your cleanup thread
void run() {
    synchronized (mutex) {
        cleanUp();
    }
}
Gannet answered 16/2, 2010 at 20:44 Comment(6)
I know that RMI executes new calls in new threads. The problem is that I don't want two remote methods to run at the same time. This includes the same method not being called more than once. I thought simply using synchronized methods would solve the problem. I read that off some forum through searching Google. Is it a certainty that RMI will ignore the synchronized directive and proceed to run remote methods concurrently?Vaientina
Thank for you for this very illustrative example. About the mutex Object. Synchronized(mutex): what does this line do? Does it acquire the provided lock for the object? Also why not use a Lock object as shown in the Concurrency tutorial? Thanks.Vaientina
synchronized (mutex) tries to accuire a so called monitor which ensures that only one thread enters the critical (protected) section. If another thread has already entered the critical section all others have to wait until it leaves the synchronized {} block. The possible ways to do this are described in the tutorial. This one is my personal preference.Gannet
(1) is not correct. First, the threading behaviour of RMI is deliberately and explicitly not specified. Second, in the Sun implementation, connection pooling can mean that successive calls from the same client are executed in the same thread. The code shown is equivalent to just synchronising the methods concerned, which would be a lot simpler.Alanis
@EJP Hm, I read this again after years. I probably tried to describe the behaviour I observed in a system I had to maintain from time to time.Gannet
@Gannet If the calls from any one client were more than 15s apart they would all execute in new server threads. But none of this is specified anywhere, deliberately.Alanis
A
0

To clarify all this confusion:

  1. If you synchronize your remote method implementations only one client can be executing at a time.

  2. If you synchronize your cleaner task on the remote object it joins (1).

  3. You can't define remote methods as static.

Alanis answered 16/5, 2011 at 1:7 Comment(0)
R
-1

You must keep in mind that RMI creates the illusion of a "remote object", but in reality there are no less than three objects: the local stub, the remote skeleton and the actual remote object. As a design trade-off this illusion is not complete and is locking only the local stub. There is no synchronization across the network. Search the internet for RMI+stub+synchronized and you will find plenty of explanations, like for instance this one:

Java RMI and synchronized methods

So you need to implement some kind of non-RMI, purely server-side synchronization yourself. Then you can invoke this pure server-side locks from your remote methods; but you need the additional level of indirection.

To test your code the easiest is to pause your threads under a good debugger like Eclipse. Eclipse will clearly show you which paused thread is holding which lock blocking which other thread(s).

Remonstrant answered 13/11, 2010 at 11:29 Comment(4)
There haven't been skeletons since 1998.Alanis
Did you mean "since Java 1998"? More seriously: yes, compile-time skeletons have been replaced with a run-time equivalent. Is it of any relevance to this page? I doubt it.Remonstrant
I meant what I wrote, and if there's a joke there I don't get it. If it isn't of relevance to this answer you should delete it from this answer. The rest of it is good.Alanis
And what 'is locking only the local stub'?Alanis

© 2022 - 2024 — McMap. All rights reserved.