我正在尝试使用RMI在Java中使用回调。
我在AWS上运行了一台服务器。我的客户端成功连接到服务器并注册回调。但是,在尝试调用它时,我在服务器端遇到以下异常:
java.rmi.NoSuchObjectException: no such object in table
at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:276)
at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:253)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:162)
at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:194)
at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:148)
at com.sun.proxy.$Proxy3.call(Unknown Source)
at server.SimpleUpdateManager.callAll(SimpleUpdateManager.java:42)
at server.Server$1.run(Server.java:77)
at java.lang.Thread.run(Thread.java:745)
我不知道为什么会这样。我已经检查过rc(客户端上的RemoteCallback实现实例)没有被垃圾回收。你知道它为什么不起作用吗?
以下是我的远程接口:
public interface RemoteCallback extends Remote {
void call() throws RemoteException;
}
和
public interface CallbackManager extends Remote{
void register(RemoteCallback uc) throws RemoteException;
void unregister(RemoteCallback uc) throws RemoteException;
void callAll() throws RemoteException;
}
相关的服务器代码:
public class SimpleUpdateManager implements CallbackManager {
private HashSet<RemoteCallback> callbacks;
public SimpleUpdateManager() {
callbacks = new HashSet<>();
}
@Override
public synchronized void register(RemoteCallback uc) {
callbacks.add(uc);
System.out.println("Callback registered");
}
@Override
public synchronized void unregister(RemoteCallback uc) {
callbacks.remove(uc);
}
@Override
public synchronized void callAll() {
ArrayList<RemoteCallback> toDelete = new ArrayList<>();
for(RemoteCallback rc : callbacks) {
try {
rc.call();
System.out.println(" Called one listener");
} catch (RemoteException re) {
re.printStackTrace();
toDelete.add(rc);
}
}
for(RemoteCallback rc :toDelete)
unregister(rc);
System.out.println("Called all listeners");
}
}
Server类的摘录:
private static SimpleUpdateManager setupUpdateManager() {
String name = "UpdateManager";
SimpleUpdateManager sum = new SimpleUpdateManager();
try {
CallbackManager exp = (CallbackManager) UnicastRemoteObject.exportObject(sum, 1100);
LocateRegistry.getRegistry().rebind(name, exp);
}
catch(RemoteException re) {
System.out.println("Setting up update manager failed");
re.printStackTrace();
}
return sum;
}
public static void runUpdateDaemon(SimpleUpdateManager sum) {
Thread updateDaemon = new Thread(new Runnable() {
@Override
public void run() {
while(true) {
try {
System.out.println("I will try calling all listeners");
sum.callAll();
TimeUnit.SECONDS.sleep(5);
}
catch (InterruptedException ie) {
break;
}
}
}
});
//updateDaemon.setDaemon(true);
updateDaemon.start();
}
客户端代码:RemoteCallback实现
public class SimpleCallback implements RemoteCallback {
@Override
public void call() throws RemoteException {
System.out.println("Callback called");
}
@Override
protected void finalize() {
System.out.println("Callback gc'd");
}
}
并注册回调
try {
rc = new SimpleCallback();
UnicastRemoteObject.exportObject(rc, 1100);
((CallbackManager) LocateRegistry.getRegistry(host).lookup("UpdateManager")).register(rc);
System.out.println("Callback registered");
}
catch (RemoteException|NotBoundException re) {
System.out.println("Cannot register callback");
re.printStackTrace();
}
答案 0 :(得分:1)
以下是问题所在:
客户端位于防火墙后面,该防火墙不允许从服务器访问端口1100,因此DGC认为客户端已经崩溃,垃圾以某种方式收集了回调。