【问题标题】:CopyOnWriteArrayList concurrent access problem on removingCopyOnWriteArrayList 删除时的并发访问问题
【发布时间】:2020-05-19 16:45:05
【问题描述】:

我正在努力寻找如何在不出现线程异常的情况下删除 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)

我有以下 Downloader

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

    }


}

ma​​in 内部:

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

你知道如何摆脱 ThreadException 吗? 谢谢

【问题讨论】:

    标签: java multithreading copyonwritearraylist


    【解决方案1】:

    您对列表的访问未同步。您有多个线程,即使 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 应该是一个同步对象,如同步列表。不是吗?
    • 是的,但您正在检查它的长度,然后处理它。在您检查长度之后但在您使用它之前,没有什么可以阻止更改列表。您必须同步关键部分。正在同步的列表仅有助于防止更新操作期间的多线程访问。多次调用它不会阻止互斥。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-11
    • 1970-01-01
    • 2012-03-31
    • 1970-01-01
    相关资源
    最近更新 更多