Rumah >Java >javaTutorial >Bagaimana untuk menyelesaikan amaran pengecualian ConcurrentModificationException dalam java

Bagaimana untuk menyelesaikan amaran pengecualian ConcurrentModificationException dalam java

王林
王林ke hadapan
2023-05-15 13:01:06881semak imbas

Analisis pengecualian

Saya percaya bahawa sesiapa yang telah menulis beberapa kod Java telah menemui pengecualian ini, yang biasanya disebabkan oleh kod berikut:

import java.util.List;
import java.util.ArrayList;

public class Test{
    public static void main(String[] args){
      List<String> list = new ArrayList<>();
      list.add("123");
      list.add("456");
      list.add("789");
      for(String obj : list){
          list.remove(obj);
      }
    }
}

Kod di atas akhirnya akan membuang java.util.ConcurrentModificationException, jadi mengapa? Mula-mula, kami menyahkompilasi kod di atas dan mendapat keputusan berikut (anda boleh mengabaikannya jika anda lebih mengetahui sintaks gula foreach):

public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
    LineNumberTable:
      line 4: 0

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class java/util/ArrayList
       3: dup
       4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
       7: astore_1
       8: aload_1
       9: ldc           #4                  // String 123
      11: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      16: pop
      17: aload_1
      18: ldc           #6                  // String 456
      20: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      25: pop
      26: aload_1
      27: ldc           #7                  // String 789
      29: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      34: pop
      35: aload_1
      36: invokeinterface #8,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
      41: astore_2
      42: aload_2
      43: invokeinterface #9,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
      48: ifeq          72
      51: aload_2
      52: invokeinterface #10,  1           // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
      57: checkcast     #11                 // class java/lang/String
      60: astore_3
      61: aload_1
      62: aload_3
      63: invokeinterface #12,  2           // InterfaceMethod java/util/List.remove:(Ljava/lang/Object;)Z
      68: pop
      69: goto          42
      72: return
    LineNumberTable:
      line 6: 0
      line 7: 8
      line 8: 17
      line 9: 26
      line 10: 35
      line 11: 61
      line 12: 69
      line 13: 72
}

Menterjemah kod di atas adalah bersamaan dengan kod berikut:

import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;

public class Test{
    public static void main(String[] args){
      List<String> list = new ArrayList<>();
      list.add("123");
      list.add("456");
      list.add("789");
      Iterator<String> iterator = list.iterator();
      while (iterator.hasNext()){
          String obj = iterator.next();
          list.remove(obj);
      }
    }
}

Kemudian kita Melihat pada iterator.hasNext() kod sumber, anda boleh mendapati bahawa baris pertama memanggil kaedah checkForComodification Mari kita semak kaedah ini:

final void checkForComodification() {
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
}

akan membuang modCount != expectedModCount pengecualian apabila keadaan adalah benar, maka keadaan ini Bagaimana ia ditubuhkan? ConcurrentModificationException

1. Mula-mula, kita semak sumber

dan kita dapati bahawa nilai modCount adalah sama dengan modCount daripada kaedah size dipanggil, List.remove juga akan dikurangkan sebanyak 1 dengan sewajarnya; modCount

2 Kemudian kita melihat sumber

, dan kita dapat melihat bahawa apabila membina expectedModCount (pelaksanaan dalaman ArrayList digunakan di sini) , terdapat penugasan pembolehubah, dan nilai Iterator Ditugaskan kepada modCount; expectedModCount

3. Akhirnya, apabila kita melaksanakan gelung dan memanggil kaedah

, List.remove berubah tetapi modCount tidak berubah Apabila gelung pertama tamat, sekeping data dipadamkan Apabila bersedia untuk memanggil kaedah expectedModCount untuk kali kedua dalam gelung, kaedah iterator.hasNext() akan membuang pengecualian, kerana pada masa ini. checkForComodification() daripada List telah berubah kepada 2, dan modCount masih 3, jadi ia akan membuang expectedModCountPengecualian;ConcurrentModificationException

Jadi bagaimana untuk menyelesaikan masalah ini? Apabila kita melihat kod sumber

(Pelaksanaan Iterator dalam ArrayList), kita dapati terdapat kaedah java.util.ArrayList.Itr dalam iterator ini yang boleh memadamkan elemen lelaran semasa dan mengubah suai kedua-dua remove dan modCount di Pada masa yang sama. Dengan cara ini, expectedModCountTiada pengecualian akan dilemparkan apabila menyemak Kod sumber kaedah checkForComodification adalah seperti berikut: remove

public void remove() {
    if (lastRet < 0)
        throw new IllegalStateException();
    checkForComodification();

    try {
        ArrayList.this.remove(lastRet);
        cursor = lastRet;
        lastRet = -1;
        expectedModCount = modCount;
    } catch (IndexOutOfBoundsException ex) {
        throw new ConcurrentModificationException();
    }
}
Antaranya, baris

akan menukar. nilai ArrayList.this.remove(lastRet);, dan kemudian ia akan diubah suai secara serentak adalah sama dengan nilai modCount; expectedModCountrreeee

Atas ialah kandungan terperinci Bagaimana untuk menyelesaikan amaran pengecualian ConcurrentModificationException dalam java. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam