1

我有两个线程都需要访问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();
            }
        }
    }
});
4

6 回答 6

7

您可能希望使用生产者消费者队列,例如ArrayBlockingQueue替代或类似的并发集合。

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

一个线程offer是 s short[],另一个take()是它们。

于 2013-05-20T15:17:26.703 回答
5

最简单的方法是将列表类型更改为线程安全列表实现

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

请注意,如果您对其进行大量变异(添加/删除),这种类型的列表并不是非常有效 - 但如果它对您有用,那是一个简单的解决方案。

如果您需要更高的效率,您可以使用同步列表来代替:

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

但是您需要同步进行迭代:

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

编辑:使用 aBlockingQueue的建议可能更好,但需要对代码进行更多更改。

于 2013-05-20T15:15:50.320 回答
2

您可能会为此使用阻塞队列而不是数组列表。

于 2013-05-20T15:18:19.740 回答
0

看看 Java 的同步支持。

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

于 2013-05-20T15:18:20.160 回答
0

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

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

于 2013-05-20T15:18:21.443 回答
0

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

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

于 2013-05-20T15:18:30.113 回答