带有writeObject的ConcurrentModificationException

时间:2011-11-18 00:27:05

标签: java android

我有以下(简化)代码由类A中的线程定期运行(每秒一次):

Socket s = new Socket(IP,PORT);
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
synchronized(this) {
   oos.writeObject(this);   //Exception HERE
   oos.flush();
}
...

通过套接字发送的对象(this)具有类B的对象作为实例变量,B具有LinkedList<Long>作为实例变量。

应用程序抛出ConcurrentModificationException

E/AndroidRuntime(681): FATAL EXCEPTION: Thread-10
E/AndroidRuntime(681): java.util.ConcurrentModificationException
E/AndroidRuntime(681): at java.util.LinkedList$LinkIterator.next(LinkedList.java:124)
E/AndroidRuntime(681): at java.util.LinkedList.writeObject(LinkedList.java:973)
E/AndroidRuntime(681): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(681): at java.lang.reflect.Method.invoke(Method.java:507)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1219)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653)
E/AndroidRuntime(681): at java.util.LinkedList.writeObject(LinkedList.java:973)
E/AndroidRuntime(681): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(681): at java.lang.reflect.Method.invoke(Method.java:507)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1219)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeFieldValues(ObjectOutputStream.java:1143)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.defaultWriteObject(ObjectOutputStream.java:413)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeHierarchy(ObjectOutputStream.java:1241)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeNewObject(ObjectOutputStream.java:1575)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObjectInternal(ObjectOutputStream.java:1847)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1689)
E/AndroidRuntime(681): at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:1653)
E/AndroidRuntime(681): at qoe.Application.connectUpdate(Application.java:194)
E/AndroidRuntime(681): at qoe.Application.access$0(Application.java:183)
E/AndroidRuntime(681): at qoe.Application$AutoUpdate.run(Application.java:217)

我使用Eclipse和AVD,Windows 7 x64在Android中运行此应用程序。提前谢谢。

编辑:经过多次测试后,我认为可能导致问题的方法如下:

/* Instance variables */
private LinkedList<Long> mylist;
private long value;
/* The incriminated method */
public synchronized void myBadMethod() {
   this.mylist.add(this.value);
}

4 个答案:

答案 0 :(得分:2)

显然,列表在序列化期间被迭代,同时B正在修改列表。您需要同步这两位代码,以便它们不能同时执行。

答案 1 :(得分:2)

这段代码:

LinkedList<Long> list_copy = this.original_list;
// ...
this.original_list = list_copy; // has no effect

可能没有按照你的想法去做。第一行使list_copy成为this.original_list引用的同一列表的引用。 (用C ++术语来说,它就像编写list<long> * list_copy_ptr = this->original_list_ptr;它实际上并没有复制列表。)最后一行确实没有效果;它只是使this.original_list成为它已经引用的列表的引用。 (如果您同时有其他未同步的代码,可能会产生影响,但除非您对volatile非常小心,否则影响不大成为你想要的。)

答案 2 :(得分:0)

您正在从两个主题修改列表。迭代器类对于在迭代它时修改List的一个线程不友好。

使用keywork synchronized(object)互相排除每个线程可能冲突访问List数据结构的代码部分。

synchronized(this){ 
     Socket s = new Socket(IP,PORT); 
     ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());    
     oos.writeObject(this);   //Exception HERE oos.flush(); ... 

}

 if(time < 30 seconds)    return; LinkedList<Long> list_copy =
 this.original_list;
     synchronized( this.Parent ){//where 'this' is class B and Parent is A
     Iterator<Long> it = list_copy.iterator();
     while(it.hasNext()) {
         Long current = it.next();
         if(something)
             it.remove();
     }
     this.original_list = list_copy; }

答案 3 :(得分:-1)

分两步解决。

1)我使用了CopyOnWriteArrayListArrayList的线程安全变体)。但是通过这种方式我又遇到了另一个问题:remove的{​​{1}}操作是not supported

2)要解决此问题,我提到this question

Iterator

缺点是这是expensive operation