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

Sab*_*bin 1 java concurrency multithreading android 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();
            }
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

Mik*_*uel 7

您可能希望使用生成器使用者队列,例如ArrayBlockingQueue替代或类似的并发集合.

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

一个线程offers short[]和另一个线程s take().


ass*_*ias 5

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

private List<short[]> list = new CopyOnWriteArrayList<short[]>();
Run Code Online (Sandbox Code Playgroud)

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

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

private List<short[]> list = Collections.synchronizedList(new ArrayList<short[]>());
Run Code Online (Sandbox Code Playgroud)

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

synchronized(list) {
    for(short[] item : list) {
        //process the data 
    }
}
Run Code Online (Sandbox Code Playgroud)

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