我正在使用ArrayList,并且如果多个线程尝试在不同步的情况下访问同一列表,我想举一个异常示例。我是在单线程应用程序中完成的,如果在迭代过程中从列表中删除一个元素,它将引发ConcurrentModificationExceptoin,但我想在多线程环境中实现相同的目的。如果有人能给我举一个例子,将不胜感激?
package com.test2;
public class ThreadTest extends Thread {
List list = new ArrayList<String>();
@Override
public void run() {
list.add("1");
list.add("2");
list.add("3");
list.add("4");
list.add("5");
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add("6");
list.add("7");
list.add("8");
Iterator<String> it = list.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
public static void main(String[] args) {
Thread th1 = new ThreadTest();
Thread th2 = new ThreadTest();
Thread th3 = new ThreadTest();
th1.start();
th2.start();
th3.start();
try {
th1.join();
th2.join();
th3.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
您正在每个线程中访问一个单独的列表实例。由于每个列表只能由一个线程访问,因此不会出现并发错误。
List list = new ArrayList<String>();
那声明了一个实例字段。因此,每次调用new ThreadTest()
都会创建一个新列表。为了使所有ThreadTest
实例使用相同的列表,请尝试创建字段static
(即class字段):
static List list = new ArrayList<String>();
至于如何可能发生的错误,看看为代码ArrayList
的add
方法:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
如果两个线程同时调用add
,则它们可以同时处理该elementData[size++] = e
语句。该size
字段没有声明volatile
; 因此,这两个线程最终可能写入elementData
数组中的同一索引。
即使size
被声明volatile
,该size++
操作也不是原子的。请参阅当同时执行线程破坏了i ++时如何建模情况?举例说明类似的操作如何size++
在多线程环境中失败。
最后,如果您不了解volatile
Java上下文中的含义和原子含义,那么在编写任何多线程代码之前,您确实需要阅读Java并发编程。这将是一项值得的投资,因为您可以通过了解这些概念来省去很多麻烦。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句