Java
 Computer >> コンピューター >  >> プログラミング >> Java

JavaのArrayListとCopyOnWriteArrayListの違いを徹底解説

Javaにおいて、ArrayListCopyOnWriteArrayListはどちらもListインターフェースの実装クラスですが、それぞれに重要な違いがあります。

本記事では、両者の主な相違点を比較表とサンプルコードを交えてわかりやすく解説します。

ArrayListとCopyOnWriteArrayListの主な違い

No.項目ArrayListCopyOnWriteArrayList
1同期(スレッドセーフ性)非同期であり、複数スレッドからの同時アクセスは保証されません。同期化されており、ある時点でオブジェクトにアクセスできるのは1つのスレッドのみです。
2パフォーマンス同期処理が不要なため、動作が高速です。同期処理のコストがかかるため、パフォーマンスは低速です。
3フェイルセーフ性イテレータはフェイルファスト(fail-fast)で、走査中にリストが変更されるとConcurrentModificationExceptionをスローします。イテレータはフェイルセーフ(fail-safe)で、走査中の変更も許容されます。
4要素の削除イテレーション中でもremove()メソッドによる要素削除が可能です。イテレーション中のremove()はサポートされておらず、実行時にUnsupportedOperationExceptionがスローされます。
5導入されたバージョンJava 1.2から存在する、より歴史のあるクラスです。Java 1.5(Java 5)で追加されたクラスです。
6所属パッケージjava.utilパッケージに属します。java.util.concurrentパッケージに属します。

サンプルコードで確認するArrayListとCopyOnWriteArrayListの挙動

ArrayListの例:ArrayListDemo.java

import java.util.*;
public class ArrayListDemo{
    public static void main(String[] args){
        ArrayList l = new ArrayList();
        l.add("A");
        l.add("B");
        l.add("C");
        Iterator itr = l.iterator();
        while (itr.hasNext()){
            String s = (String)itr.next();
            if (s.equals("B")){
                itr.remove(); // イテレーション中の削除が可能
            }
        }
        System.out.println(l);
    }
}

実行結果

[A,C]

このように、ArrayListではイテレーション中にitr.remove()を呼び出しても問題なく動作し、要素「B」が正常に削除されます。

CopyOnWriteArrayListの例:CopyOnWriteArrayListDemo.java

import java.util.concurrent.CopyOnWriteArrayList;
import java.util.*;
class CopyOnWriteArrayListDemo extends Thread {
    static CopyOnWriteArrayList l = new CopyOnWriteArrayList();
    public static void main(String[] args) throws InterruptedException{
        l.add("A");
        l.add("B");
        l.add("C");
        Iterator itr = l.iterator();
        while (itr.hasNext()){
            String s = (String)itr.next();
            System.out.println(s);
            if (s.equals("B")){
                // 実行時例外がスローされる
                itr.remove();
            }
            Thread.sleep(1000);
        }
        System.out.println(l);
    }
}

実行結果

A
B
Exception in thread "main" java.lang.UnsupportedOperationException

CopyOnWriteArrayListの場合、イテレーション中にitr.remove()を呼び出すと、実行時にUnsupportedOperationExceptionがスローされることが確認できます。これは、CopyOnWriteArrayListのイテレータが元のリストのスナップショットを参照する仕組みになっており、変更操作をサポートしていないためです。

使い分けのポイント

  • シングルスレッド環境や読み取り中心の処理: 高速なArrayListが適しています。
  • マルチスレッド環境で頻繁に読み取り、更新はまれなケース: スレッドセーフなCopyOnWriteArrayListが適しています。ただし、書き込みのたびに内部配列のコピーが発生するため、更新頻度が高い場合は注意が必要です。

用途に応じて適切なクラスを選択することで、安全性とパフォーマンスのバランスを取ることができます。

  1. JavaのArrayList.clear()とremoveAll()の違いを徹底解説

    JavaのArrayListクラスは、Listインターフェースの可変長配列(リサイズ可能な配列)実装であり、null値の格納も許容しています。 このクラスには要素を削除するためのメソッドとしてclear()とremoveAll()が用意されています。どちらもリストから要素を取り除く点では共通していますが、動作内容には明確な違いがあります。本記事では、それぞれの使い方とサンプルコードを交えながら違いを解説します。 clear()メソッドとは clear()メソッドは、現在のListオブジェクトからすべての要素を一括で削除します。引数を受け取らず、呼び出すだけでリストが空の状態になります。 サンプ

  2. JavaでのArrayListとHashSetの違いを徹底解説!使い分けのポイントも紹介

    HashSetとArrayListは、どちらもJavaコレクションフレームワークにおいて最も重要なクラスの一つです。それぞれ特徴が異なるため、用途に応じた適切な使い分けが求められます。本記事では、ArrayListとHashSetの主な違いを6つの観点から比較し、実際のサンプルコードとともにわかりやすく解説します。ArrayListとHashSetの違い一覧No.項目ArrayListHashSet1実装インターフェースListインターフェースを実装しています。Setインターフェースを実装しています。2内部構造内部的には配列(動的配列)を使って実装されています。内部的にはHashMapを使って