![](/img/trans.png)
[英]Is externally synchronized ArrayList thread safe if its fields are not volatile?
[英]ArrayList is not Thread safe even with synchronized block?
我正在尝试使用ArrayList的Producer和Consumer问题(我知道Arraylist不是线程安全的),并且确保将列表与synchronized
关键字放在一起,但仍然陷入ConcurrentModificationException
。 这是错误
开始的生产者请提供工作详细信息:TestJob工作已完成:TestJob线程“ consumer”中的异常java.util.ArrayList $ Itr.checkForComodification中的java.util.ConcurrentModificationException(java.util.ArrayList $ Itr.next(未知)源代码)在test.thread.Consumer.run(Consumer.java:25)在java.lang.Thread.run(未知源)
这是我的代码:
package test.thread;
import java.util.List;
import java.util.Scanner;
public class Producer implements Runnable {
private List<String> jobs = null;
public Producer(List<String> jobs) {
this.jobs = jobs;
}
@Override
public void run() {
System.out.println("Starting Producer");
while(true)
{
synchronized (jobs) {
try {
if (jobs.isEmpty()) {
System.out.println("Please provide the job details: ");
Scanner scanner = new Scanner(System.in);
String job = scanner.nextLine();
jobs.add(job);
scanner.close();
jobs.notifyAll();
Thread.sleep(4000);
} else {
jobs.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
package test.thread;
import java.util.List;
public class Consumer implements Runnable {
private List<String> jobs = null;
public Consumer(List<String> list) {
this.jobs = list;
}
@Override
public void run() {
while(true)
{
synchronized (jobs) {
try {
if (jobs.isEmpty()) {
jobs.wait();
} else {
for (String job : jobs) {
System.out.println("Job completed: " + job);
jobs.remove(job);
Thread.sleep(2000);
}
jobs.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
package test.thread;
import java.util.ArrayList;
import java.util.List;
public class TestThread {
public static void main(String...strings )
{
List<String> list = new ArrayList<String>();
Producer producer = new Producer(list);
Consumer consumer = new Consumer(list);
Thread prodThread = new Thread(producer, "producer");
Thread consThread = new Thread(consumer, "consumer");
prodThread.start();
consThread.start();
}
}
您无法使用增强的for语句从要迭代的列表中删除项目。
如果要删除元素,则需要一个显式的迭代器来调用remove:
Iterator<String> it = jobs.iterator();
while (it.hasNext()) {
String job = it.next();
System.out.println("Job completed: " + job);
it.remove();
Thread.sleep(2000);
}
当然,像这样从ArrayList中删除项目效率非常低(它是O(n^2)
),并且由于必须显式同步,因此容易出错。 您应该考虑改用某种BlockingQueue
。
尽管您收到ConcurrentModificationException
您的问题根本不是多线程引起的。
实际上,这是有问题的代码:
for (String job : jobs) {
System.out.println("Job completed: " + job);
jobs.remove(job);
Thread.sleep(2000);
}
for
循环将在作业上使用Iterator
,同时您直接(在结构上)修改jobs
(即,不通过Iterator
)。 这意味着Iterator
不再是定义良好的对象,它将引发此异常以告知您。
如果在迭代集合时需要从集合中删除元素,则需要使Iterator
明确:
Iterator<String> jobIterator = job.iterator();
while (jobIterator.hasNext()) {
String job = jobIterator.next();
// ... stuff ...
jobIterator.remove(); // remove the last object that was returned by next()
}
您的并发修改不是由线程引起的。
for (String job : jobs) {
System.out.println("Job completed: " + job);
jobs.remove(job);
Thread.sleep(2000);
}
该行jobs.remove(job);
迭代时修改ArrayList。 迭代器仅在为此使用Iterators remove方法完成后才允许修改列表。
for( Iterator<String> iter = jobs.iterator(); iter.hasNext(); )
{
String job = iter.next();
iter.remove();
}
您不是因为并发而获得ConcurrentModificationException:您只需在循环中删除项目:
for (String job : jobs) {
System.out.println("Job completed: " + job);
jobs.remove(job);
使用迭代器删除项目。
您应该使用CopyOwWriteArrayList
来防止在使用列表Iterator
发生ConcurrentModificationException
(代码中的for-each循环在CopyOwWriteArrayList
使用它)
暂时无法删除元素,请使用迭代器方法删除。
Iterator<String> it = jobs.iterator();
while(it.hasNext()) {
String job = it.next();
....
it.remove();
...
}
这样可以避免并发修改异常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.