繁体   English   中英

ArrayList即使同步块也不安全吗?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM