Example of exception in ArrayList?

我的梦境 提交于 2019-12-25 03:26:26

问题


I am using ArrayList and I want an example of Exception in case if multiple threads try to access the same list without synchronization ? I done this in single threaded application in which if we remove an element from list while iteration it throws ConcurrentModificationExceptoin but I want to achieve the same in multi threaded environment. If anyone could give me an example of that would be highly appreciated ?

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




    }

}

回答1:


You're accessing a separate list instance in each of your threads. Since each list is only accessed by one thread, you can't get a concurrency error.

List list = new ArrayList<String>();

That declares an instance field. Therefore, each call to new ThreadTest() creates a new list. In order to make all the ThreadTest instances use the same list, try making the field static (i.e. a class field):

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

As for how an error can happen, take a look at the code for ArrayList's add method:

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

If two threads call add at the same time, they could process the elementData[size++] = e statement at the same time. The size field is not declared volatile; therefore, the two threads could end up writing to the same index in the elementData array.

Even if size were declared volatile, the size++ operation is not atomic. See How to model a situation, when i++ is corrupted by simultaneously executing threads? for an example of how an operation like size++ can fail in a multithreaded environment.

Finally, if you don't understand what volatile and atomic mean in the Java context, you really need to read up on concurrent programming in Java before you write any multithreaded code. It will be a worthwhile investment as you'll save yourself a lot of headaches by understanding these concepts.




回答2:


Quick answer:

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

Output:

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)

Note: As @Braj and @DaoWen said you are using different instances. Either use their suggestions or pass the list variable in the constructor of your class (ThreadTest).




回答3:


If I understand your question, yes change this

List list = new ArrayList<String>();

by using Collections.synchronizedList(List) to something like (and don't use raw types),

List<String> list = Collections.synchronizedList(new ArrayList<String>());

From the javadoc,

Returns a synchronized (thread-safe) list backed by the specified list. In order to guarantee serial access, it is critical that all access to the backing list is accomplished through the returned list.

It is imperative that the user manually synchronize on the returned list when iterating over it:

List list = Collections.synchronizedList(new ArrayList());
...
synchronized (list) {
  Iterator i = list.iterator(); // Must be in synchronized block
  while (i.hasNext())
    foo(i.next());
  }
}



回答4:


it throws ConcurrentModificationExceptoin but I want to achieve the same in multi threaded environment

I am asking how to get an exception in multithreaded environment - From comment

Since you are creating separate copy of List for each thread hence there is no chance to get this exception.

Just make the List as shared resource then you will encounter this exception:

sample code:

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

Output:

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)


来源:https://stackoverflow.com/questions/24947530/example-of-exception-in-arraylist

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!