我正在使用ArrayList,如果多个线程试图在没有同步的情况下访问同一个列表,我想要一个Exception示例?我在单线程应用程序中完成了这个,如果我们在迭代时从列表中删除一个元素,它会抛出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();
}
}
}
答案 0 :(得分:1)
快速回答:
public class Main {
public static void main(String[] args) throws InterruptedException
{
final ArrayList<String> list = new ArrayList<String>();
list.add("Item 1");
list.add("Item 2");
list.add("Item 3");
list.add("Item 4");
Thread thread = new Thread(new Runnable()
{
@Override
public void run ()
{
for (String s : list)
{
System.out.println(s);
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
});
thread.start();
Thread.sleep(2000);
list.remove(0);
}
}
输出:
Item 1
Item 2
Exception in thread "Thread-0" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
at java.util.ArrayList$Itr.next(ArrayList.java:831)
at com.akefirad.tests.Main$1.run(Main.java:34)
at java.lang.Thread.run(Thread.java:745)
注意: 正如@Braj和@DaoWen所说,你正在使用不同的实例。要么使用他们的建议,要么在类的构造函数中传递list变量(ThreadTest)。
答案 1 :(得分:1)
您正在每个线程中访问单独的列表实例。由于每个列表只能由一个线程访问,因此无法获得并发错误。
List list = new ArrayList<String>();
宣告实例字段。因此,每次调用new ThreadTest()
都会创建一个新列表。为了使所有ThreadTest
个实例使用相同的列表,请尝试创建字段static
(即类字段):
static List list = new ArrayList<String>();
至于 如何发生错误,请查看the code for ArrayList
's add
method:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
如果两个线程同时调用add
,他们可以同时处理elementData[size++] = e
语句。 The size
field is not declared volatile
;因此,两个线程最终可能会写入elementData
数组中的相同索引。
即使声明size
volatile
,size++
操作也不是原子。有关size++
之类的操作在多线程环境中如何失败的示例,请参阅 How to model a situation, when i++ is corrupted by simultaneously executing threads? 。
最后,如果您不了解Java上下文中的volatile
和原子意味着什么,那么在编写任何多线程代码之前,您确实需要阅读Java中的并发编程。这将是一项值得的投资,因为你可以通过理解这些概念来节省很多麻烦。
答案 2 :(得分:0)
如果我理解你的问题,可以改变这个
List list = new ArrayList<String>();
使用Collections.synchronizedList(List)
之类的内容(和不使用raw types),
List<String> list = Collections.synchronizedList(new ArrayList<String>());
来自javadoc,
返回由指定列表支持的同步(线程安全)列表。为了保证串行访问,必须通过返回的列表完成对后备列表的所有访问。
当迭代时,用户必须手动同步返回的列表:
List list = Collections.synchronizedList(new ArrayList()); ... synchronized (list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); } }
答案 3 :(得分:0)
它会抛出ConcurrentModificationExceptoin,但我希望在多线程环境中实现相同的目标
我问如何在多线程环境中获得异常 - 来自评论
由于您为每个线程创建List
的单独副本,因此无法获得此异常。
只需将List
设为共享资源,您就会遇到此异常:
示例代码:
public class Main{
public static void main(String[] args){
// shared by all the threads.
final List<String> list = new ArrayList<String>();
class ThreadTest extends Thread {
@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());
}
}
}
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();
}
}
}
输出:
Exception in thread "Thread-2" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at com.test.TestDemo$1ThreadTest.run(TestDemo.java:390)