我有两个线程都需要访问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();
}
}
}
});
答案 0 :(得分:7)
您可能希望使用类似producer consumer的ArrayBlockingQueue
队列或类似的并发集合。
生产者 - 消费者问题(也称为有界缓冲问题)是多进程同步问题的典型示例。该问题描述了两个进程,生产者和使用者,他们共享一个用作队列的通用固定大小缓冲区。制作人的工作是生成一段数据,将其放入缓冲区并重新开始。同时,消费者一次一件地消费数据(即,将其从缓冲器中移除)。问题是确保生产者不会尝试将数据添加到缓冲区中,如果它已满并且消费者不会尝试从空缓冲区中删除数据。
答案 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)
您可以要求Collections类将当前的ArrayList包装在同步列表中。