0

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




    }

}
songyuanyao
  • 169,198
  • 16
  • 310
  • 405
Peter
  • 185
  • 6
  • 21
  • 1
    better to share your code as well. – Braj Jul 25 '14 at 03:27
  • are you asking about how to solve this ConcurrentModificationExceptoin? – Braj Jul 25 '14 at 03:27
  • 1
    Braj : I am asking how to get an exception in multithreaded environment – Peter Jul 25 '14 at 03:29
  • 2
    in the same way as you are doing in single threaded enviornment. – Braj Jul 25 '14 at 03:29
  • Braj : code added.No, I want to get an exception using this code becuase we say we cannot use ArrayList in the Multithreaded environment. So I am trying to achieve that... – Peter Jul 25 '14 at 03:31
  • Make sure the threads are accessing the *same* list. – user2864740 Jul 25 '14 at 03:33
  • 1
    you might want a `for(int i=0; i<1000000; i++) { list.add(i); }` there, instead of just 8 elements and hoping to create a concurrent threading problem. – Mike 'Pomax' Kamermans Jul 25 '14 at 03:33
  • Mike 'Pomax' Kamermans- done as you suggested but it worked fine. it took some time, but got no exceptions. – Peter Jul 25 '14 at 03:35
  • @Peter - Are you on a multi-core machine? You might not going to get threading issues if you don't actually have hardware that can run multiple threads concurrently. – DaoWen Jul 25 '14 at 03:39

4 Answers4

1

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).

Rad
  • 4,292
  • 8
  • 33
  • 71
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.

Community
  • 1
  • 1
DaoWen
  • 32,589
  • 6
  • 74
  • 101
0

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());
  }
}
Community
  • 1
  • 1
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
  • Thanks for the code Elliott Frisch, but I am trying to get an exception. I am doing POC on Java Doc statement "If we use ArrayList in Multithreaded environment we'll get an concurrent exception." – Peter Jul 25 '14 at 06:46
0

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)
Community
  • 1
  • 1
Braj
  • 46,415
  • 5
  • 60
  • 76
  • Braj : Could you tell me where are you declaring your list ? – Peter Jul 25 '14 at 06:44
  • just outside the class `ThreadTest` to make it shared resources. – Braj Jul 25 '14 at 06:45
  • I am afraid that we can declare a list outside the class in Java. It's giving compilation error. Are you sure we can declare the list outside the class in Java ? – Peter Jul 25 '14 at 07:19
  • Don't know how are you doing it, I have shared a running code. – Braj Jul 27 '14 at 04:48