我有一个ArrayList
String
个,两个线程同时访问列表。
以下代码段的输出结果如何?
public static void main(String[] args) {
final ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < 100; i++) {
list.add("Number" + i);
}
new Thread() {
public void run() {
for (String s : list) {
System.out.println(s);
}
}
}.start();
new Thread() {
public void run() {
list.remove("Number5");
}
}.start();
}
我尝试使用相同的代码,使用Arraylist
同步Collections.synchronizedList(list)
。它仍然在抛出java.util.ConcurrentModificationException
。
答案 0 :(得分:3)
synchronizedList
的Javadoc明确指出:
当迭代时,用户必须手动同步返回的列表:
List list = Collections.synchronizedList(new ArrayList()); ... synchronized (list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); }
不遵循此建议可能会导致非确定性行为。
由于在此代码中,您在迭代它时从List
中删除(在不同的线程中,但它是List
的相同实例),ConcurrentModificationException
将被抛出。
使用Collections.synchronizedList
,以下代码可以正常运行。
final List<String> list = Collections.synchronizedList(new ArrayList<String>());
for (int i = 0; i < 100; i++) {
list.add("Number" + i);
}
new Thread() {
public void run() {
synchronized (list) {
for (String s : list) {
System.out.println(s);
}
}
}
}.start();
new Thread() {
public void run() {
synchronized (list) {
list.remove("Number5");
}
}
}.start();
答案 1 :(得分:2)
您可以使用syncrhonized关键字锁定list
对象。
同步关键字
它的总体目的是只允许一个线程 一次进入特定的代码部分,从而允许我们 例如,保护变量或数据不被损坏 来自不同线程的同时修改。
所以这对你有用:
public static void main(String[] args) {
...
new Thread() {
public void run() {
synchronized(list){
for (String s : list) {
System.out.println(s);
}
}
}
}.start();
new Thread() {
public void run() {
synchronized(list){
list.remove("Number5");
}
}
}.start();
}
NB:这取决于你想要什么逻辑btw。 您是否希望在迭代时从列表中删除或?你希望这两个任务按顺序发生吗?
答案 2 :(得分:1)
你是iterating
(在第一个线程中)和updating
(在第二个线程中)两个不同线程中的相同list
对象,因此总有(可能性)它会抛出java.util.ConcurrentModificationException
。
在java Iterator中本质上是快速失败的,因此一旦他们意识到下划线结构已被更改,它们就会失败并出现ConcurrentModificationException
异常。
如果要根据需要使用相同的列表对象,可以考虑使用两个线程synchronized(list)
方法中的run
进行同步。
public void run() {
synchronized(list) {
for (String s : list) {
System.out.println(s);
}
}
}
public void run() {
synchronized(list) {
list.remove("Number5");
}
}
答案 3 :(得分:0)
我认为您应该使用Vector
而不是ArrayList
来ThreadSafe
加上使用Iterator
来浏览您的列表。