0

同じ JVM 内のオブジェクトのリストをシリアライズおよびデシリアライズする際に問題があります。正確には、現在、私のオブジェクトAlphabetは、次のルールを持つオブジェクトへの同じ参照を保持しています。

    VMID instanceId = new VMID();  //used in readResolve to identify persitent instances

    public Alphabet (int capacity, Class entryClass) {
        this.map = new gnu.trove.TObjectIntHashMap (capacity);
        this.entries = new ArrayList (capacity);
        this.entryClass = entryClass;
        // someone could try to deserialize us into this image (e.g., by RMI).  Handle this.
        deserializedEntries.put (instanceId, this);
    }

    public VMID getInstanceId() {
        return instanceId;
    } // for debugging

    public void setInstanceId(VMID id) { this.instanceId = id; }

    // Serialization
    private static final long serialVersionUID = 1;

    private static final int CURRENT_SERIAL_VERSION = 1;

    private void writeObject (ObjectOutputStream out) throws IOException {
        out.writeInt (CURRENT_SERIAL_VERSION);
        out.writeInt (entries.size());
        for (int i = 0; i < entries.size(); i++) {
            out.writeObject (entries.get(i));
        }
        out.writeBoolean (growthStopped);
        out.writeObject (entryClass);
        out.writeObject(instanceId);
    }

    private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException {
        int version = in.readInt ();
        int size = in.readInt();
        entries = new ArrayList (size);
        map = new gnu.trove.TObjectIntHashMap (size);
        for (int i = 0; i < size; i++) {
            Object o = in.readObject();
            map.put (o, i);
            entries. add (o);
        }
        growthStopped = in.readBoolean();
        entryClass = (Class) in.readObject();
        if (version >0 ){ // instanced id added in version 1S
            instanceId = (VMID) in.readObject();
        }
    }

    private transient static HashMap deserializedEntries = new HashMap();
    /**
     * This gets called after readObject; it lets the object decide whether
     * to return itself or return a previously read in version.
     * We use a hashMap of instanceIds to determine if we have already read
     * in this object.
     * @return
     * @throws ObjectStreamException
     */

    public Object readResolve() throws ObjectStreamException {
        Object previous = deserializedEntries.get(instanceId);
        if (previous != null){
            //System.out.println(" ***Alphabet ReadResolve:Resolving to previous instance. instance id= " + instanceId);
            return previous;
        }
        if (instanceId != null){
            deserializedEntries.put(instanceId, this);
        }
        //System.out.println(" *** Alphabet ReadResolve: new instance. instance id= " + instanceId);
        return this;
    }

オブジェクトのリストを逆シリアル化した後、ある時点でアルファベットの参照が一致しなくなりました。以下を使用してチェックを行いました。

for (Instance i: finalTrainingDocs){
    if (!i.getTargetAlphabet().equals(finalTraining.getTargetAlphabet())){
        System.out.println("not equals");
        System.out.println(i.getTargetAlphabet().getInstanceId() + " " + finalTraining.getTargetAlphabet().getInstanceId());
    }
    finalTraining.add(i);
    counter++;
    System.out.println("counter " + counter);
}

そして、次の結果が返されました

counter 237
counter 238
counter 239
not equals
3ce62156867eb540:6b7f0de5:141e51fcd67:-7ffa 3ce62156867eb540:6b7f0de5:141e51fcd67:-7ffa

VMId を見ると、それらは同じなので、上記のロジックのように同じオブジェクトではないでしょうか? 助けてくれてありがとう。

4

2 に答える 2

0

1 つの可能性は、競合状態になっていることです。つまり、2 つのスレッドがdeserializedEntries同時にハッシュマップを更新しています。その結果、Alphabet同じ値を持つ 2 つのインスタンスが発生する可能性がありinstanceIdます。

deserializedEntriesこれを防ぐには、 asを宣言するだけvolatileでは不十分です。(実際、不適切な同期により、ハッシュマップの内部データ構造が破損する可能性さえあります。)


あなたのしていることは良い考えだとは思えません。この脆弱性 (修正するにはより重い同期が必要です) に加えて、ハッシュマップがメモリ リークであるという問題があります。Alphabetインスタンスが重複することを受け入れ、equalsこれに対処するためにオーバーライドすることで、パフォーマンスが向上すると思います。

于 2013-10-23T12:06:25.263 に答える
-1

バージョンに基づいてinstanceIdを読んでいます

if (version >0 ){ // instanced id added in version 1S
    instanceId = (VMID) in.readObject();
}

したがって、ここでも同じ条件を適用する必要があります

 if (CURRENT_SERIAL_VERSION >0 ){ 
      out.writeObject(instanceId);
于 2013-10-23T11:58:16.690 に答える