【问题标题】:java.util.ConcurrentModificationException on ArrayList in multi thread多线程中 ArrayList 上的 java.util.ConcurrentModificationException
【发布时间】:2016-02-11 11:59:04
【问题描述】:

您好在这里定义了两个线程 EvenThread1 和 OddThread2。 EvenThread1 正在打印 ArrayList 中的偶数,并从列表中删除相应的值。相同的 OddThread2 也打印来自相同 ArrayList 的奇数和列表中相应的删除值。 问题是当我执行 2 或 3 次 java.util.ConcurrentModificationException 出现在控制台上时。 即使我正在使用有效检查从列表中删除该值。

if (j.intValue() >= 0)
{
    it.remove();
}

我知道它为什么会出现,但我无法在这个程序中解决。 您能否建议我如何在以下程序中解决此异常并进行解释?

 package MultiThreading;

    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;

    public class Eg2
    {

        public static void main(String[] args)
        {
        new EvenThread1();
        new OddThread2();

        }
    }

    class EvenThread1 implements Runnable
    {

        List<Integer> list = Services1.getNum();

        EvenThread1()
        {
        Thread th = new Thread(this);
        th.start();
        }

        @Override
        public void run()
        {
        Iterator<Integer> it = list.iterator();
        while (it.hasNext())
        {
            Integer j = (Integer) it.next();
            int a = j % 2;
            if (a == 0)
            {
            System.out.println("Even: " + j.intValue());
            if (j.intValue() >= 0)
            {
                it.remove();
                System.out.println("List Data=" + list);
            }

            }

        }

        }

    }

    class OddThread2 implements Runnable
    {

        List<Integer> list = Services1.getNum();

        OddThread2()
        {
        Thread th = new Thread(this);
        th.start();
        }

        @Override
        public void run()
        {
        Iterator<Integer> it = list.iterator();
        while (it.hasNext())
        {
            Integer j = (Integer) it.next();
            int a = j % 2;
            if (a != 0)
            {
            System.out.println("Odd: " + j.intValue());
            if (j.intValue() >= 0)
            {
                it.remove();
                System.out.println("List Data=" + list);
            }

            }

        }

        }

    }

    abstract class Services1
    {

        static List<Integer> list = new ArrayList<Integer>();

        static
        {
        for (int i = 0; i < 20; i++)
        {
            list.add(i);
        }
        }

        static public List<Integer> getNum()
        {
        return list;
        }

    }

【问题讨论】:

  • 实际上没有办法并行执行此操作。您需要同步访问列表,获取迭代器并删除偶数;然后同步对列表的访问,获取迭代器并删除奇数(或相反)。在两个线程中这样做是没有意义的,因为每个线程都需要独占访问列表。

标签: java multithreading arraylist


【解决方案1】:
    static List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());

你需要像上面的代码一样同步你的list,因为这将是并发调用。

【讨论】:

  • 请注意,在列表上使用迭代器时,他还需要同步,根据synchronizedList的javadoc
  • 嗨,你几乎可以作为一个 java 编程概念,但即使它不工作,它仍然说同样的异常。但是我得到了解决方案,我们必须通过同步块锁定每个线程中的列表对象。示例:synchronized(list){.....} 但你也是正确的,应该也可以工作,但是这里不工作,我不知道为什么?
【解决方案2】:

ConcurrentLinkedDeque 是一个支持并发操作的类似列表的数据结构。它可以返回报告Spliterator.CONCURRENTSpliterator。这是一个好的开始。但是要使解决方案即使使用这些,您也需要能够创建两个Spliterators,一个用于偶数,另一个用于赔率,并且它们必须能够以某种方式跟踪它们各自的元素。泛化:返回 SpliteratorSet 给定实现分区策略的东西,并确保所有它们都跟踪自己的元素。

严格来说,这并非不可能。但你不能开箱即用。您必须进行一些有趣(即棘手且容易出错)的编码才能使这样的事情发生。

玩得开心,完成后把它贴在github 或类似的地方。 :-)

【讨论】:

    猜你喜欢
    • 2011-07-05
    • 2010-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-10
    • 1970-01-01
    • 2013-05-06
    • 2014-12-12
    相关资源
    最近更新 更多