Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/201.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在两个线程中使用列表会导致java.util.ConcurrentModificationException_Java_Android_Multithreading_Android Studio_Iterator - Fatal编程技术网

在两个线程中使用列表会导致java.util.ConcurrentModificationException

在两个线程中使用列表会导致java.util.ConcurrentModificationException,java,android,multithreading,android-studio,iterator,Java,Android,Multithreading,Android Studio,Iterator,得到了一个带有主线程和myThread的代码。当按下主线程中的某个按钮时,将调用myThread.start()onCameraFrame不断获取帧的颜色值并将其保存到ArrayList rV。在myThread中,我需要sout(rV),用它做一些事情,每6秒清洁一次rV 我使用迭代器来做这样的事情,但仍然在myThread中的sout行中得到java.util.ConcurrentModificationException。请注意,它发生在随机时间。例如,按下按钮后,sout可能会正常工作1

得到了一个带有主线程和myThread的代码。当按下主线程中的某个按钮时,将调用myThread.start()
onCameraFrame
不断获取帧的颜色值并将其保存到
ArrayList rV
。在myThread中,我需要
sout(rV)
,用它做一些事情,每6秒清洁一次rV

我使用迭代器来做这样的事情,但仍然在myThread中的
sout
行中得到
java.util.ConcurrentModificationException
。请注意,它发生在随机时间。例如,按下按钮后,sout可能会正常工作1秒或5分钟,然后-异常

我的建议是,rV由myThread和主线程(onCameraFrame)同时使用。所以它崩溃了

我需要一个建议。为此挣扎了几个小时

这是密码

public class Camera extends Activity implements CvCameraViewListener2 {

@Override
public void onCreate(Bundle savedInstanceState) {
    ..
    View.OnClickListener onClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ..
            myThread = new Thread(mRunnable);
            myThread.start();
        }
    ..
}

Runnable mRunnable = new Runnable() {
    @Override
    public void run() {
        Thread thisThread = Thread.currentThread();
        while (myThread==thisThread) {
            try {thisThread.sleep(6000);} 
            catch ..}
            mButton.post(new Runnable() {
                @Override
                public void run() {
                    /*logging*/
                    if (!rV.isEmpty()){
                        System.out.println("rV"+"("+rV.size()+")={"+rV.toString()+"}");
                    }

                    *//*clean data*//*
                    for (Iterator<Double> it = rV.iterator(); it.hasNext();) {
                        while(it.hasNext()){
                            Double t = it.next();
                            it.remove();
                        }
                    }
                }
            });
        }
    }
};

public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
    ..
    if (condition) {
        rV.add(somevalue);
    }
    return inputFrame.rgba();
}
公共类摄影机扩展活动实现CvCameraViewListener2{
@凌驾
创建时的公共void(Bundle savedInstanceState){
..
View.OnClickListener OnClickListener=新建视图。OnClickListener(){
@凌驾
公共void onClick(视图v){
..
myThread=新线程(mRunnable);
myThread.start();
}
..
}
Runnable mRunnable=新的Runnable(){
@凌驾
公开募捐{
Thread thisThread=Thread.currentThread();
while(myThread==thisThread){
试试{thisThread.sleep(6000);}
捕获..}
mButton.post(新Runnable(){
@凌驾
公开募捐{
/*伐木*/
如果(!rV.isEmpty()){
System.out.println(“rV”+(“+rV.size()+”)={“+rV.toString()+”}”);
}
*//*干净数据*//*
for(Iterator it=rV.Iterator();it.hasNext();){
while(it.hasNext()){
双t=it.next();
it.remove();
}
}
}
});
}
}
};
CameraFrame上的公用Mat(CvCameraViewFrame输入框){
..
如果(条件){
增加(某个值);
}
返回inputFrame.rgba();
}

您必须同步对数据结构的访问。一个好办法是使用信号量(java.concurrent包)。 信号量s=新信号量(1);->1许可证

在你的线程中,你获得了许可证:s.aquire()-如果没有许可证,线程停止在这里。在你的工作完成后,你释放了许可证:s.release()。
也就是说,现在只有一个线程可以访问数据。这里有两个潜在的问题。第一个:ConcurrentModificationException,在迭代
ArrayList
时从
ArrayList
中删除。请参阅以解决第一个问题

第二个问题是,
ArrayList
不是线程安全的。因此,在对“rV”进行迭代时,如果它不引发异常,则无法对其进行修改。请改用
java.util.concurrent
包中的线程安全实现。例如,使用.See获取更多详细信息

@DDsix建议使用。这在某些情况下可能是合适的,但在其他情况下不合适。的JavaDocs对此进行了解释:

所有可变操作(添加、设置等)通过创建基础数组的新副本来实现。这通常成本太高,但当遍历操作的数量远远超过变异时,可能比替代方法更有效,并且在您无法或不想同步遍历,但需要排除concurre之间的干扰时,这一点非常有用nt线程


您可以使用基本上是线程安全的ArrayList,也可以使用集合.synchronizedList(new ArrayList());来创建列表(这不是并发的,而是同步的)

您尝试过使用队列(Dequeue)吗?您可以从populator线程推送所有新数据,然后从另一端弹出数据?读取数据线程可以弹出数据,对其执行某些操作,然后根据需要将其填充到另一个集合中。大多数线程安全集合将允许您执行脏读(读取时不锁定),但删除和插入将需要锁定。
ArrayBlockingQueue
当然没有这个问题……您指的是哪个集合?@AustinD,我尝试了
ArrayBlockingQueue
(比如说,ABK)我遇到了另一个问题。我无法在主线程中声明ABK,因为它的大小(帧数颜色值)直接取决于不断变化的摄像头fps。因此,我尝试在myThread中创建ABK,并得到了相同的问题原因。为了将rV克隆到ABK,我必须在myThread中循环rV。我将此代码粘贴到myThread中。
ArrayBlockingQueue rVBQ=new ArrayBlockingQueue(rV.size());for(双d:rV){rVBQ.add(d);}
为什么不直接使用
rV.clear()
然后删除
for(Iterator it=rV.Iterator();it.hasNext();){while(it.hasNext()){Double t=it.next();it.remove();}
好吧,我不明白你为什么这么说-迭代器使用很好,错误在
sout(rV.size+rV.toString)处突然出现
。无论如何,我注意到ABQ不必和rV一样大小,必须指定的是ABQ的最大容量。我将其设置为1000,因此我根本没有使用ArrayList,并且能够在Main和myThread中访问ABQ,没有任何例外。感谢您的提示!