CopyOnWriteArrayList concurrent access problem on removing

426 Views Asked by At

I am struggling to find how to remove an Element of a CopyOnWriteAccess without getting a thread exception.

Exception in thread "Thread-3649" java.lang.ArrayIndexOutOfBoundsException: Index 4 out of bounds for length 4
    at java.base/java.util.concurrent.CopyOnWriteArrayList.elementAt(CopyOnWriteArrayList.java:386)
    at java.base/java.util.concurrent.CopyOnWriteArrayList.remove(CopyOnWriteArrayList.java:479)
    at com.mycompany.playmatehunter.Downloader.init(Downloader.java:28)
    at com.mycompany.playmatehunter.Downloader.run(Downloader.java:19)
    at java.base/java.lang.Thread.run(Thread.java:834)

I have the following Downloader class

public class Downloader extends Thread{
    private CopyOnWriteArrayList<String> url_list;
    private String chemin;

    public Downloader( CopyOnWriteArrayList<String> l, String chemin)
    {
        this.url_list = l;
        this.chemin = chemin;
    }

    public void run()
    {
        init();   
    }

    public synchronized void init() // the list is already synchronized
    {
        if (!url_list.isEmpty())
        {
            int alea = (int)(Math.random()*url_list.size());
            System.out.println(this.getName()+"removes the link nbr "+url_list.get(alea));
            url_list.remove(alea);
        }

    }


}

And inside the main :

CopyOnWriteArrayList<String> index = new CopyOnWriteArrayList( FileToList("/index/index.txt") );

        while( index.size() != 0)
        {
            List<Thread> tg = new ArrayList<Thread>();            
            for(int i=0;i<7;i++)
            {
                Thread t=new Thread(new Downloader(index, ""));
                t.start();
                tg.add(t);
            }

            for(Thread t: tg) 
                t.join();
        }

Do you know how to get rid of ThreadException? Thank you

1

There are 1 best solutions below

2
Burak Serdar On BEST ANSWER

Your access to the list is not synchronized. You have multiple threads, and even though the init() method is synchronized, the synchronization is on the thread instance, not on a common object, so it is useless. If you need to ensure mutual exclusion among threads, you have to synchronize on a common object:

 public void init() // No synchronization here
    {
       synchronized(url_list) { // synchronize on a common object
        if (!url_list.isEmpty())
        {
            int alea = (int)(Math.random()*url_list.size());
            System.out.println(this.getName()+"removes the link nbr "+url_list.get(alea));
            url_list.remove(alea);
        }
      }

    }