当我使用我的包装类序列化然后反序列化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();
}
答案 0 :(得分:0)
我能想到的一个原因是对Map的并发修改。说出执行以下语句后删除时会发生什么?
stream.writeInt(map.size());
首先说当检索Map大小时,地图中存在的元素数量是2,但是说其他一些线程会同时删除地图中的一个元素,所以现在地图中存在的元素数量为1那么在流中写入的内容只有一个键值对(2个对象)。
但有趣的是,我们在读取大小中读到的是2个键值对(4个对象),因为我们将大小读为2,我们尝试使用2个键值对,即使写入的只是一个键 - 值对。
这是我们在该领域的许多客户所经历的事情。后来都被证明是一个并发的修改问题。所以我建议你检查一下。
entrySet的Javadoc不会确认任何修改都会引发并发修改异常。
返回此映射中包含的映射的Set视图。该集由地图支持,因此对地图的更改将反映在集中,反之亦然。如果在对集合进行迭代时修改了映射(除非通过迭代器自己的删除操作,或者通过迭代器返回的映射条目上的setValue操作),迭代的结果是未定义的。该集支持元素删除,它通过Iterator.remove,Set.remove,removeAll,retainAll和clear操作从地图中删除相应的映射。它不支持add或addAll操作。