当我对包装类进行序列化然后反序列化map.subMap时,我将遇到OptionalDataException。

似乎OptionalDataException与基元有关,但是在映射中,我总是将对象装箱的基元正确。那么我该如何解决呢?

编辑:添加了同步块

public class SerializeableSubMap<K, V> implements NavigableMap<K, V>, Serializable {
    private static final long serialVersionUID = -7002458872266068959L;
    private NavigableMap<K, V> map;

    public SerializeableSubMap(NavigableMap<K, V> map) {
        this.map = map;
    }

private void writeObject(ObjectOutputStream stream) throws IOException {
    synchronized (map) {
        stream.writeInt(map.size());
        Iterator<Entry<K, V>> itr = map.entrySet().iterator();
        Entry<K, V> next;

        while (itr.hasNext()) {
            next = itr.next();
            stream.writeObject(next.getKey());
            stream.writeObject(next.getValue());
        }
    }
    //stream.close();
}

private void readObject(ObjectInputStream stream) throws IOException {
        int size = stream.readInt();
        map = new ConcurrentSkipListMap<K, V>();

        for(int i = 0; i < size; i++) {
            try {
                // get OptionalDataException here!
                map.put((K) stream.readObject(), (V) stream.readObject());
            } catch (Exception e) {
                throw new IOException(e);
            }
        }
    }

    // delegate map interface methods to map object
}


编辑2:

private void writeObject(ObjectOutputStream stream) throws IOException {
    synchronized (map) {
        int s =  map.size();

        stream.writeInt(map.size());
        Iterator<Entry<K, V>> itr = map.entrySet().iterator();
        Entry<K, V> next;

        int i=0;
        while (itr.hasNext()) {
            next = itr.next();
            stream.writeObject(next.getKey());
            stream.writeObject(next.getValue());
            i++;
        }

        if (s != i) {
            throw new ConcurrentModificationException();
        }
    }
    //stream.close();
}

最佳答案

我能想到的原因之一是对地图的并发修改。假设执行以下语句后执行删除操作,会发生什么情况?

stream.writeInt(map.size());


最初说的是,当检索到地图大小时,地图中存在的元素数为2,但是说其他线程同时删除了地图中的一个元素,因此现在地图中存在的元素数为1。被写入流中的只有一对键值对(2个对象)。

但是有趣的是,在读取大小时读取的是2个键值对(4个对象),因为我们将大小读取为2,所以即使写入的只是一个键值对,我们也会尝试消耗2个键值对。

这是我们与该领域许多客户一起经历的。后来,所有这些都变成了并发修改问题。所以我建议您检查一下。

entrySet的Javadoc不会确认任何修改都会引发并发修改异常。


  Set> entrySet()
  
  返回此映射中包含的映射的Set视图。该集合由地图支持,因此对地图的更改会反映在集合中,反之亦然。如果在对集合进行迭代时修改了映射(通过迭代器自己的remove操作或通过迭代器返回的映射条目上的setValue操作除外),则迭代的结果不确定。该集合支持元素删除,该元素通过Iterator.remove,Set.remove,removeAll,retainAll和clear操作从映射中删除相应的映射。它不支持add或addAll操作。

关于java - 自定义(de-)序列化方法抛出java.io.OptionalDataException,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30707374/

10-11 12:18