ConcurrentModificationException与全局变量但不是局部变量局部变量

时间:2022-06-30 16:49:31

In the following function I have declared local variables allPeopel and itr(they are overriding global variables). If I comment out the local variables (between the Astrixes below), then a ConcurrentModificationError is thrown. However, if I use local variables instead of global variables then the code works fine. I don't understand why this is the case? There are many other functions in the class so I'm trying to use global variables for more efficient code.

在下面的函数中,我声明了局部变量allPeopel和itr(它们覆盖了全局变量)。如果我注释掉局部变量(在下面的Astrixes之间),则抛出ConcurrentModificationError。但是,如果我使用局部变量而不是全局变量,那么代码工作正常。我不明白为什么会这样呢?该类中还有许多其他函数,因此我尝试使用全局变量来获得更高效的代码。

   public void removeAPerson(){
        int id;
        Scanner sc = new Scanner(System.in);
        System.out.print("Enter ID of person to delete > ");
        id = sc.nextInt();
        sc.nextLine();
        System.out.println();

        /*************************************/
        ArrayList<Person> allPeople;
        allPeople = Person.getAllPeople();
        Iterator itr = allPeople.iterator();
        /*************************************/

        while(itr.hasNext()){
            Person obj = (Person) itr.next();
            int ID = obj.getID2();
            if(ID == id){
                itr.remove();
                break;
            }
        }
    }

2 个解决方案

#1


0  

Using local variables, each time a thread calls your method creates a new instance of these variables, that are not available to any other thread (unless you specifically allow for passing the references). So, no other thread can modify your objects.

使用局部变量,每次线程调用您的方法时都会创建这些变量的新实例,这些变量不可用于任何其他线程(除非您特别允许传递引用)。因此,没有其他线程可以修改您的对象。

Using global (I think you mean instance variables, attributes), all of the threads that have access to your object has access to those attributes of the object (let it be directly, let it be by running your object methods) and can modify them while your other thread is running the iteration. Since the iterator can detect when the Collection that is being iterated has been modified, when this happens it throws the exception (which means nothing else that "I was iterating all of the objects of the collection but these objects are no longer the same so this is too confusing and I fail".

使用global(我认为你的意思是实例变量,属性),所有有权访问对象的线程都可以访问对象的那些属性(让它直接运行,让它通过运行你的对象方法)并可以修改它们而你的另一个线程正在运行迭代。由于迭代器可以检测到正在迭代的Collection何时被修改,当发生这种情况时它会抛出异常(这意味着没有别的“我正在迭代集合的所有对象但是这些对象不再相同所以这个太混乱了,我失败了“。

#2


2  

This is a sketch of what you probably have:

这是你可能拥有的草图:

public class MyClass {
  List<Person> persons = new ArrayList<>();
  Iterator<Person> iter = strs.iterator();

  public void addPerson(Person p) {
    persons.add(p);
  }

  public void removePerson() {
    ... your posted code ...
  }


  public static void main(String... args) {
    MyClass c = new MyClass();
    c.addPerson(new Person());
    c.removePerson();
  }

What happens is that you instantiate the iterator only once, then add something to the list, then use the iterator. It never makes sense to reuse a global instance of iterator like that. Specifically, after you instantiate it, you must not change the list except through the iterator itself.

发生的事情是你只将iterator实例化一次,然后在列表中添加一些东西,然后使用迭代器。重用像这样的迭代器的全局实例是没有意义的。具体来说,在实例化之后,除非通过迭代器本身,否则不得更改列表。

Using a global variable is one thing, but using a global instance of iterator is another. Both are wrong, but the latter is fatal.

使用全局变量是一回事,但使用迭代器的全局实例是另一回事。两者都是错的,但后者是致命的。

#1


0  

Using local variables, each time a thread calls your method creates a new instance of these variables, that are not available to any other thread (unless you specifically allow for passing the references). So, no other thread can modify your objects.

使用局部变量,每次线程调用您的方法时都会创建这些变量的新实例,这些变量不可用于任何其他线程(除非您特别允许传递引用)。因此,没有其他线程可以修改您的对象。

Using global (I think you mean instance variables, attributes), all of the threads that have access to your object has access to those attributes of the object (let it be directly, let it be by running your object methods) and can modify them while your other thread is running the iteration. Since the iterator can detect when the Collection that is being iterated has been modified, when this happens it throws the exception (which means nothing else that "I was iterating all of the objects of the collection but these objects are no longer the same so this is too confusing and I fail".

使用global(我认为你的意思是实例变量,属性),所有有权访问对象的线程都可以访问对象的那些属性(让它直接运行,让它通过运行你的对象方法)并可以修改它们而你的另一个线程正在运行迭代。由于迭代器可以检测到正在迭代的Collection何时被修改,当发生这种情况时它会抛出异常(这意味着没有别的“我正在迭代集合的所有对象但是这些对象不再相同所以这个太混乱了,我失败了“。

#2


2  

This is a sketch of what you probably have:

这是你可能拥有的草图:

public class MyClass {
  List<Person> persons = new ArrayList<>();
  Iterator<Person> iter = strs.iterator();

  public void addPerson(Person p) {
    persons.add(p);
  }

  public void removePerson() {
    ... your posted code ...
  }


  public static void main(String... args) {
    MyClass c = new MyClass();
    c.addPerson(new Person());
    c.removePerson();
  }

What happens is that you instantiate the iterator only once, then add something to the list, then use the iterator. It never makes sense to reuse a global instance of iterator like that. Specifically, after you instantiate it, you must not change the list except through the iterator itself.

发生的事情是你只将iterator实例化一次,然后在列表中添加一些东西,然后使用迭代器。重用像这样的迭代器的全局实例是没有意义的。具体来说,在实例化之后,除非通过迭代器本身,否则不得更改列表。

Using a global variable is one thing, but using a global instance of iterator is another. Both are wrong, but the latter is fatal.

使用全局变量是一回事,但使用迭代器的全局实例是另一回事。两者都是错的,但后者是致命的。