我有以下(简化)代码由类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);
}
答案 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)我使用了CopyOnWriteArrayList
(ArrayList
的线程安全变体)。但是通过这种方式我又遇到了另一个问题:remove
的{{1}}操作是not supported。
2)要解决此问题,我提到this question:
Iterator
缺点是这是expensive operation。