2013-10-23 58 views
0

我有问题序列化和反序列化在同一个JVM中的对象列表。确切的说,现在我的目标持同样引用的Alphabet对象,它具有以下规则:java反序列化和序列化在相同的过程

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; 
    } 

现在AFTE我的对象名单,反序列化,在某些点上字母引用犯规投其所好。我做了检查使用以下:

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,因为它们是相同的,应该不会是同一个对象,如上面的逻辑?感谢您的帮助。

+0

那些writeObject()和readObject()方法似乎不会比默认情况下添加任何值。 – EJP

+0

似乎喜欢它。它来自一个叫做木槌的开源库,所以我不确定作者的意图是什么 – goh

+0

我不认为有足够的代码来弄清楚这里发生了什么。例如,如何实现'Alphabet.equals',以及VMID的代码在哪里? –

回答

-1

您是基于版本阅读实例Id

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

所以在相同的条件需要在这里申请

if (CURRENT_SERIAL_VERSION >0){ 
     out.writeObject(instanceId); 
+1

为什么你是这么认为的?将它添加到哪里?说明。 – EJP

+0

字节码,版本一直是1,所以我不认为这可能会导致问题...? – goh

0

一种可能性是,你有一个竞争条件;即两个线程同时更新deserializedEntries散列表。这可能会导致您有两个Alphabet实例的值等于instanceId

声明deserializedEntriesvolatile不足以防止这种情况。 (事实上​​,你的不足同步甚至可能会导致被损坏HashMap中的内部数据结构。)


我不相信,你在做什么是一个好主意。除了这种脆弱性(这需要更多的重量级同步来修复)之外,你还有问题就是hashmap是内存泄漏。我怀疑你会得到更好的性能,接受Alphabet实例得到重复,并重写equals来处理这个问题。