Пример исключения в ArrayList?

Я использую ArrayList и мне нужен пример исключения в случае, если несколько потоков пытаются получить доступ к одному и тому же списку без синхронизации? Я сделал это в однопоточном приложении, в котором, если мы удаляем элемент из списка во время итерации, он выбрасывает 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();
        }




    }

}

4 ответа

Решение

Вы получаете доступ к отдельному экземпляру списка в каждой из ваших тем. Поскольку каждый список доступен только одному потоку, вы не можете получить ошибку параллелизма.

List list = new ArrayList<String>();

Это объявляет поле экземпляра. Поэтому каждый звонок new ThreadTest() создает новый список. Для того, чтобы сделать все ThreadTest экземпляры используют тот же список, попробуйте сделать поле static (т.е. поле класса):

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

Что касается того, как может произойти ошибка, взгляните на код для ArrayList "s add метод:

 public boolean add(E e) {
     ensureCapacityInternal(size + 1);  // Increments modCount!!
     elementData[size++] = e;
     return true;
 }

Если две темы называют add в то же время они могли бы обрабатывать elementData[size++] = e заявление в то же время. size поле не объявлено volatile; следовательно, два потока могут закончить запись в один и тот же индекс в elementData массив.

Даже если size были объявлены volatile, size++ операция не атомарная. См. Как смоделировать ситуацию, когда i++ поврежден из-за одновременного выполнения потоков? для примера того, как операция, как size++ может потерпеть неудачу в многопоточной среде.

Наконец, если вы не понимаете, что volatile и атомарное среднее в контексте Java, вам действительно нужно ознакомиться с параллельным программированием в Java, прежде чем писать какой-либо многопоточный код. Это будет выгодное вложение, поскольку вы избавите себя от множества головных болей, поняв эти концепции.

Быстрый ответ:

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, вы используете разные экземпляры. Либо используйте их предложения, либо передайте переменную списка в конструкторе вашего класса (ThreadTest).

Если я понимаю ваш вопрос, да измените это

List list = new ArrayList<String>();

используя Collections.synchronizedList(List) что-то вроде (и не используйте сырые типы),

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

он выбрасывает 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)
Другие вопросы по тегам