如何在访问java ArrayList时阻止两个线程冲突?

时间:2013-05-20 15:13:30

标签: java android multithreading concurrency synchronization

我有两个线程都需要访问ArrayList<short[]>实例变量。

当新数据到达时,一个线程将通过回调异步将short[]项添加到列表中:void dataChanged(short[] theData)

另一个线程将定期检查列表是否包含项目,如果是,它将迭代所有项目,处理它们,并从阵列中删除它们。

如何设置它以防止两个线程之间的冲突?

这个人为的代码示例目前抛出java.util.ConcurrentModificationException

//instance vairbales
private ArrayList<short[]> list = new ArrayList<short[]>();

//asynchronous callback happening on the thread that adds the data to the list
void dataChanged(short[] theData) {
    list.add(theData);
}

//thread that iterates over the list and processes the current data it contains
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {

        while (true) {

            for(short[] item : list) {
                //process the data 
            }

            //clear the list to discared of data which has been processed. 
            list.clear(); 

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
});

6 个答案:

答案 0 :(得分:7)

您可能希望使用类似producer consumerArrayBlockingQueue队列或类似的并发集合。

  

生产者 - 消费者问题(也称为有界缓冲问题)是多进程同步问题的典型示例。该问题描述了两个进程,生产者和使用者,他们共享一个用作队列的通用固定大小缓冲区。制作人的工作是生成一段数据,将其放入缓冲区并重新开始。同时,消费者一次一件地消费数据(即,将其从缓冲器中移除)。问题是确保生产者不会尝试将数据添加到缓冲区中,如果它已满并且消费者不会尝试从空缓冲区中删除数据。

一个帖子offershort[] s和另一个take()个。

答案 1 :(得分:4)

最简单的方法是将列表类型更改为thread safe list implementation

private List<short[]> list = new CopyOnWriteArrayList<short[]>();

请注意,如果你对它进行大量改变(添加/删除),这种类型的列表效率不是很高 - 但是如果它适用于你,这是一个简单的解决方案。

如果您需要更高的效率,可以使用synchronized list代替:

private List<short[]> list = Collections.synchronizedList(new ArrayList<short[]>());

但是你需要同步迭代:

synchronized(list) {
    for(short[] item : list) {
        //process the data 
    }
}

编辑:使用BlockingQueue的提案可能更好,但需要对代码进行更多更改。

答案 2 :(得分:2)

你可能会考虑blockingqueue而不是arraylist。

答案 3 :(得分:0)

看看Java的同步支持。

This page涵盖了在指定对象上同步一组语句。也就是说:只有一个线程可以同时执行在该对象上同步的任何部分,其他所有部分都必须等待。

答案 4 :(得分:0)

您可以使用synchronized块,但我认为最好的解决方案是不要在线程之间共享可变数据。

让每个线程在自己的空间中写入,并在工人完成时收集并汇总结果。

答案 5 :(得分:0)

http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#synchronizedList%28java.util.List%29

您可以要求Collections类将当前的ArrayList包装在同步列表中。