7

jdk1.6を使用してRMIベースの分散システムに取り組んでいます。

ConcurrentModificationExceptionオブジェクトのシリアル化に失敗したときに、RMI ランタイム内でそのスレッドでエラーが発生することがあります。リモートメソッドから返されるオブジェクトを同時に更新することで、その例外を簡単に再現できます。

しかし、問題は、これらの呼び出しの発信元が見つからないことです。RMI 例外が書き込まれstderrます (リモート オブジェクト メソッドを終了した後、ランタイム コード内のサーバー側でキャプチャされます) が、クライアント サービスに一致する例外はありません (それが正当なリモート呼び出しである場合は、RemoteException適切な原因が発生します)。

これらの例外の唯一の違いは、「RMI TCP 接続 (<接続数>)-<クライアント エンドポイント情報>」のようなスレッドではなく、「RMI TCP 接続 (アイドル)」スレッドで発生していることです。

RMI の「アイドル」スレッドとは何かについての手がかりはありますか? openjdk ソース内でそのようなものを見つけることができませんでした。

Upd: 再現された例外スタック トレースを追加しています。これは、説明されている状況で通常見られるものです。

サーバー側のコンソールには次のように表示されます。

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 TCP Connection(idle)」という名前で RMI の接続プールに作成されます。これらのいずれかが使用されると、実行に使用されているランナブルは、スレッドの名前を「RMI TCP Connection(n)」に変更します。ここnで、 は処理される接続番号 (連続番号) であり、ランナブルの名前を「idle」に戻します。最後にブロックします。したがって、「RMI TCP Connection(idle)」というラベルの付いたトレースは、ランナブルが接続スレッドとして名前を変更する前、または名前が元に戻された後に来る必要があります。

それがどのように可能か私に尋ねないでください。あなたの問題に対する実際の答えは、あなたの質問ではないにしても、オブジェクトが同時に返されている間にオブジェクトを変更しないことです;-)

于 2012-06-07T01:37:32.723 に答える
1

私はその底に着きました。問題は次の 2 つの場合に発生します。

  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 属性を読み取るときにそのような例外が発生した場合、スタックトレースは表示されませんが、属性値は Unavailable として表示されます。

于 2012-06-07T11:35:53.310 に答える