即使使用synchronized块,ArrayList也不是线程安全的吗?

时间:2016-03-23 11:12:56

标签: java multithreading collections

我正在使用ArrayList尝试生产者和消费者问题(我知道Arraylist不是线程安全的),我确保我使用snapshots关键字列出但仍然进入synchronized。这是错误

  

启动制作人请提供作业详细信息:TestJob Job   已完成:线程“消费者”中的TestJob异常   java.util.ConcurrentModificationException at   java.util.ArrayList $ Itr.checkForComodification(Unknown Source)at   java.util.ArrayList $ Itr.next(未知来源)at   test.thread.Consumer.run(Consumer.java:25)at   java.lang.Thread.run(未知来源)

这是我的代码:

ConcurrentModificationException

6 个答案:

答案 0 :(得分:3)

您无法从使用增强型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代替。

答案 1 :(得分:3)

虽然你得到ConcurrentModificationException,但问题不是由多线程引起的。

实际上这是有问题的代码:

for (String job : jobs) {
    System.out.println("Job completed: " + job);
    jobs.remove(job);
    Thread.sleep(2000);
}

for循环将在作业上使用Iterator,同时您直接(在结构上)修改jobs(即不通过Iterator)。这意味着Iterator不再是明确定义的,它会抛出此异常来告诉您。{/ p>

如果您需要在迭代时删除集合中的元素,则需要明确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()
}

答案 2 :(得分:2)

您的并发修改不是由线程引起的。

    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();
     } 

答案 3 :(得分:1)

你得到ConcurrentModificationException不是因为并发:你只需要在循环中删除项目:

for (String job : jobs) {
     System.out.println("Job completed: " + job);
     jobs.remove(job);

使用迭代器删除项目。

答案 4 :(得分:0)

在使用列表CopyOwWriteArrayList时,您应该使用ConcurrentModificationException来阻止Iterator(代码中的每个循环都会在引擎盖下使用它)

答案 5 :(得分:0)

无法删除元素,请使用迭代器方法删除。

Iterator<String> it = jobs.iterator();
while(it.hasNext()) {
      String job = it.next();
      ....
      it.remove();
      ...
}

这将避免concurrentModificationException。