mrmapleleaf
@mrmapleleaf (Kaede Maruyama)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

JavaのArrayListのスレッドセーフの挙動について

解決したいこと

ArrayListのスレッドについての疑問を解消したい。

こんにちは。
現在、JavaSilver資格取得に向けて勉強しております。
黒本にて「ArrayListの要素を拡張for文を使って削除するとどうなるか」
の問題が2パターンありました。
回答としては
①:「「A」のみ出力される」(remove()によってリストの内容だけがズレて、拡張for文のカーソルは動かない為)

②:「実行時に例外がスローされる」(1つのリストを拡張for文二つのマルチスレッド環境で操作しようとした為、「ConcurrentModificationException」が発生)
となっていました。

ArrayListはスレッドセーフのクラスで無いので②の回答には納得できるのですが、その回答の解説に「ConcurrentModificationExceptionは、シングルスレッド環境下でも発生する」と記載がありました。この解説に沿うならば、①の方でもこの例外が発生するのではないかと考えているのですが、なぜ正常に実行されるのでしょうか?

稚拙な質問で申し訳ございませんが、ご教授いただけますと幸いです。よろしくお願い致します。

問題のコード①

 public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");
        for(String str : list) {
            if("B".equals(str)) {
                list.remove(str);
            } else {
                System.out.println(str);
            }
        }
}

問題のコード②

 public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("A");
        list.add("B");
        list.add("C");
        list.add("D");
        list.add("E");
        for(String str : list) {
            if("C".equals(str)) {
                list.remove(str);
            }
        }
        for(String str : list) {
            System.out.println(str);
        }
}

自分で試したこと

  • ①の方の条件文を「"C".equals(str)」にして実行した所、「ConcurrentModificationException」が発生しました。
  • ②の方の条件文を「"D".equals(str)」にして実行した所、以下の様に出力されました。
A
B
C
E
0

1Answer

一旦細かい説明を抜きにして、JavaSilverの資格的に覚えたほうがいい内容のみをお伝えしますと
拡張for文の中でListの最後から2番目の要素を削除する場合はConcurrentModificationExceptionは発生しません。

では、なぜ上記のケースで例外が発生しないかという理由についてですが、
java.util.ArrayListのソースを読んでみるのが一番わかり易いと思います。
他の方の書かれている記事ですが、下記のようなサイトがわかりやすいので是非参考にしてみてください。

[Java]新人向けにjava.util.ArrayListで発生するConcurrentModificationExceptionについて解説
Java Silver合格への道 ~拡張for文の中でArryaList.removeしても例外がスローされない謎に迫る~

もし読んでみてもわからない場合は、わからなかったところなどを教えて下さい。

0Like

Comments

  1. @mrmapleleaf

    Questioner

    to K2491pさん
    初めまして。回答いただきありがとうございます。
    すでに記事やサイトで説明されていたのですね...私の調査不足でした。
    参考にさせていただきます。情報提供ありがとうございました!
  2. @mrmapleleaf

    Questioner

    to K2491pさん
    提供していただいた記事とソースコード確認いたしました。
    本当ならば例外が発生しなければならないのが仕様として正しいのに、
    最後から2番目の要素が削除される時だけロジック的におかしくなってしまっていると、理解しました。(ある種のバグ?)
    情報提供頂きありがとうございました!
  3. 理解していただけたようで何よりです!
    ご指摘いただいたとおり、ある種のバグっぽいですが、
    これがjava言語としての仕様みたいですね。
    JavaSilver資格頑張ってください!

Your answer might help someone💌