【问题标题】:How can I stop two threads colliding when accessing java ArrayList?访问java ArrayList时如何阻止两个线程冲突?
【发布时间】:2013-05-20 15:13:29
【问题描述】:

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

【问题讨论】:

    标签: java android multithreading concurrency synchronization


    【解决方案1】:

    您可能希望使用 producer consumer 队列,例如 ArrayBlockingQueue 或类似的并发集合。

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

    一个线程 offers short[]s 和另一个 take()s 他们。

    【讨论】:

      【解决方案2】:

      最简单的方法是将列表类型更改为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 的建议可能更好,但需要对代码进行更多更改。

      【讨论】:

        【解决方案3】:

        您可能会为此查看 blockingqueue 而不是数组列表。

        【讨论】:

          【解决方案4】:

          看看 Java 的同步支持。

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

          【讨论】:

            【解决方案5】:

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

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

            【讨论】:

              【解决方案6】:

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

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

              【讨论】:

                猜你喜欢
                • 2013-10-20
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多