Java 删除时CopyOnWriteArrayList并发访问问题

Java 删除时CopyOnWriteArrayList并发访问问题,java,multithreading,copyonwritearraylist,Java,Multithreading,Copyonwritearraylist,我正在努力寻找如何在不出现线程异常的情况下删除CopyOnWriteAccess的元素 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:

我正在努力寻找如何在不出现线程异常的情况下删除CopyOnWriteAccess的元素

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)
我有以下下载类

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

    }


}
公共类下载程序扩展线程{
私有CopyOnWriteArrayList url\u列表;
私有字符串chemin;
公共下载程序(CopyOnWriteArrayList l,字符串)
{
this.url_list=l;
this.chemin=chemin;
}
公开募捐
{
init();
}
public synchronized void init()//列表已同步
{
如果(!url\u list.isEmpty())
{
intalea=(int)(Math.random()*url_list.size());
System.out.println(this.getName()+“删除链接nbr”+url_list.get(alea));
url_list.remove(alea);
}
}
}
中:

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();
        }
CopyOnWriteArrayList index=新的CopyOnWriteArrayList(FileToList(“/index/index.txt”);
而(index.size()!=0)
{
List tg=new ArrayList();

对于(int i=0;i您对列表的访问未同步。您有多个线程,即使同步了
init()
方法,同步也在线程实例上,而不是在公共对象上,因此它是无用的。如果您需要确保线程之间的互斥,则必须在公共对象上同步:

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

    }


您对列表的访问未同步。您有多个线程,即使已同步
init()
方法,同步也在线程实例上,而不是在公共对象上,因此它是无用的。如果需要确保线程之间的互斥,则必须在公共对象上同步:

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

    }


谢谢,但有件事我不明白。CopyOnWriteAccess应该是一个像同步列表一样的同步对象。不是吗?是的,但你正在检查它的长度,然后再处理它。没有什么阻止你在检查长度之后,但在处理它之前更改列表。你必须同步关键部分。Th同步e list只会有助于防止更新操作期间的多线程访问。当您多次调用它时,它不会防止互斥。谢谢,但有一点我不明白。CopyOnWriteAccess应该是一个与同步列表类似的同步对象。不是吗?是的,但您正在检查它的长度和大小然后处理它。在检查长度之后,但在处理之前,没有什么可以阻止更改列表。您必须同步关键部分。正在同步的列表仅有助于在更新操作期间防止多线程访问。当您多次调用它时,它不会阻止互斥。