自定义(反)序列化方法抛出 java.io.OptionalDataException
Custom (de-) serialize method throws java.io.OptionalDataException
当我使用包装 class 序列化然后反序列化 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();
}
我能想到的一个原因是对地图的并发修改。说一下下面语句执行后有delete会怎样?
stream.writeInt(map.size());
假设最初检索地图大小时,地图中存在的元素数为 2,但假设其他线程同时删除了地图中的一个元素,那么现在地图中存在的元素数是1。那么写入流中的只是一个键值对(2个对象)。
但有趣的是,我们在读取大小中读取的是2个键值对(4个对象),因为我们读取的大小为2,所以我们尝试使用2个键值对,即使写入的只是一个键值对。
这是我们在该领域的许多客户中遇到的事情。后来都证明是并发修改的问题。所以我建议你检查一下。
entrySet 的 Javadoc 未确认任何修改都会引发并发修改异常。
Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation, or through the setValue operation on a map entry returned by the iterator) the results of the iteration are undefined. The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll and clear operations. It does not support the add or addAll operations.
当我使用包装 class 序列化然后反序列化 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();
}
我能想到的一个原因是对地图的并发修改。说一下下面语句执行后有delete会怎样?
stream.writeInt(map.size());
假设最初检索地图大小时,地图中存在的元素数为 2,但假设其他线程同时删除了地图中的一个元素,那么现在地图中存在的元素数是1。那么写入流中的只是一个键值对(2个对象)。
但有趣的是,我们在读取大小中读取的是2个键值对(4个对象),因为我们读取的大小为2,所以我们尝试使用2个键值对,即使写入的只是一个键值对。
这是我们在该领域的许多客户中遇到的事情。后来都证明是并发修改的问题。所以我建议你检查一下。
entrySet 的 Javadoc 未确认任何修改都会引发并发修改异常。
Returns a Set view of the mappings contained in this map. The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation, or through the setValue operation on a map entry returned by the iterator) the results of the iteration are undefined. The set supports element removal, which removes the corresponding mapping from the map, via the Iterator.remove, Set.remove, removeAll, retainAll and clear operations. It does not support the add or addAll operations.