7

我正在使用 jdk1.6 开发基于 RMI 的分布式系统。

有时ConcurrentModificationException,当 RMI 运行时无法序列化对象时,我会看到该线程上发生的错误。我可以通过同时更新从远程方法返回的对象来轻松重现该异常。

但问题是我找不到这些电话的来源。RMI 异常被写入stderr(在它退出远程对象方法后在运行时代码中的服务器端捕获),但在客户端服务中没有匹配的异常(如果这是一个合法的远程调用,RemoteException则会引发适当的原因)。

这些异常的唯一不同之处在于它们发生在“RMI TCP Connection(idle)”线程上,而不是像“RMI TCP Connection(<connection count>)-<client endpoint info>”这样的线程上。

关于 RMI 中那些“空闲”线程的任何线索?我没有在 openjdk 源代码中找到这样的。

更新:我正在添加一个异常堆栈跟踪作为复制,这是您通常在所描述的情况下看到的。

服务器端控制台显示:

Exception dispatching call to [-3534448f:12f54948b7f:-7fff, 349678755005857493] in thread "RMI TCP Connection(6)-x.x.x.x" at Thu Apr 14 16:15:13 BST 2011:
java.util.ConcurrentModificationException
    at java.util.ArrayList.writeObject(ArrayList.java:573)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:945)
    at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1469)
    at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1400)
    at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
    at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:330)
    at sun.rmi.server.UnicastRef.marshalValue(UnicastRef.java:274)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:315)
    at sun.rmi.transport.Transport$1.run(Transport.java:159)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:662)

向调用者抛出客户端大小异常:

java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
    java.io.EOFException
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:173)
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
    at $Proxy0.getData(Unknown Source)
    at Clnt.main(Clnt.java:11)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:115)
Caused by: java.io.EOFException
    at java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2553)
    at java.io.ObjectInputStream.skipCustomData(ObjectInputStream.java:1899)
    at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1873)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1752)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
    at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:306)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:155)
    ... 9 more
4

2 回答 2

4

线程在 RMI 的连接池中创建,名称为“RMI TCP Connection(idle)”。当使用其中之一时,用于执行的可运行将线程重命名为“RMI TCP Connection(n)”,其中n正在处理的连接号(序列号),并在可运行的中重命名为“空闲”最后阻塞。因此,任何标记为“RMI TCP Connection(idle)”的跟踪都必须在可运行对象将其重命名为连接线程之前出现,或者在它被重命名回来之后出现。

不要问我怎么可能。如果不是您的问题,您的问题的实际答案是不要在同时返回对象时修改它们;-)

于 2012-06-07T01:37:32.723 回答
1

我到了它的底部。问题发生在两种情况下:

  1. 当封送返回值引发一些异常并且该异常又包含易于并发修改的对象时。UnicastServerRef尝试将原因写入(已经损坏的)返回流和原因ConcurrentModificationException
  2. 当方法引发异常并且此异常无法序列化ConcurrentModificationException(或任何其他运行时异常)时。
    这个异常一直向上堆栈,并被线程池捕获和记录,而不是 RMI 运行时(这就是为什么Exception dispatching call to开头没有行)。这解释了线程名称是空闲的,因为从 RMI 的角度来看,它已经返回到池中。

这是真正的异常,实际上与在第一行和实际调用跟踪方面再现的异常显示的有点不同:

Exception in thread "RMI TCP Connection(idle)" java.util.ConcurrentModificationException
 at java.util.ArrayList.writeObject(ArrayList.java:573)
 at sun.reflect.GeneratedMethodAccessor6.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:597)
 at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:945)
 at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1461)
 at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
 at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509)
 at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
 at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
 at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509)
 at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
 at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
 at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1509)
 at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1474)
 at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1392)
 at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1150)
 at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:326)
 at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:343)
 at sun.rmi.transport.Transport$1.run(Transport.java:159)
 at java.security.AccessController.doPrivileged(Native Method)
 at sun.rmi.transport.Transport.serviceCall(Transport.java:155)
 at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:535)
 at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:790)
 at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:649)
 at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
 at java.lang.Thread.run(Thread.java:619)

它没有为原始问题提供太多线索,所以我必须等待客户端异常出现在某个时候才能解决这个问题。
如果通过 jconsole 读取 JMX 属性时发生这种异常,它不会显示堆栈跟踪,但会显示属性值不可用。

于 2012-06-07T11:35:53.310 回答