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

JavaにおけるHashtableとConcurrentHashMapの違い

JavaにおけるHashtableとConcurrentHashMapの違い

Javaでマップ(Map)をマルチスレッド環境下で扱う際、「Hashtable」と「ConcurrentHashMap」のどちらを使うべきか迷ったことはありませんか?どちらもスレッドセーフなMap実装ですが、ロックの仕組みやパフォーマンス、nullの扱いなどに大きな違いがあります。本記事では、両者の特徴を比較表とサンプルコードを交えて詳しく解説します。

Hashtableとは

Hashtableは、JDK 1.1から提供されているレガシーなクラスで、Mapインターフェースの基本的な実装の一つです。すべてのpublicメソッドが同期(synchronized)されているため、スレッドセーフな動作が保証されています。しかし、その反面、あるスレッドがロックを保持している間は他のスレッドがアクセスできず、パフォーマンスが大きく低下します。また、キーおよび値にnullを許容せず、要素の順序も保証されません。

ConcurrentHashMapとは

ConcurrentHashMapは、JDK 1.5で導入されたjava.util.concurrentパッケージのクラスです。マップへの追加や更新の際に、バケット単位(セグメント/フラグメントと呼ばれる)にのみロックを適用します。そのため、読み取り操作はほぼロックフリーで並行実行でき、書き込み操作も異なるバケット間であれば同時に処理できます。この細粒度のロック設計により、高い並行性と優れたスループットを実現しています。

HashtableとConcurrentHashMapの比較表

No.項目HashtableConcurrentHashMap
1導入時期JDK 1.1で導入されたレガシーなスレッドセーフクラスJDK 1.5で導入された並行処理向けクラス
2ロック方式コレクション全体に対してロックを取得追加・更新時にバケット単位(セグメント)にのみロックを適用
3パフォーマンスロック競合が発生しやすく、ConcurrentHashMapより遅い細粒度ロックにより高速でスループットが高い
4nullの扱いキー・値ともにnull不可キー・値ともにnull不可
5イテレータフェイルファスト(fail-fast)フェイルセーフ(弱い一貫性)

補足:ConcurrentHashMapがnullを許可しないのは、マルチスレッド環境では「get()がnullを返した場合に、キーが存在しないのか、値としてnullが格納されているのかを判別できない」という曖昧さを避けるためです。

Hashtableの使用例

import java.util.Hashtable;
import java.util.Map;

public class HashtableExample {
    public static void main(String[] args) {
        // Hashtableの作成
        Hashtable<String, String> map = new Hashtable<>();
        map.put("HCL", "100");
        map.put("DELL", "200");
        map.put("IBM", "300");

        // マップの内容を出力
        for (Map.Entry<String, String> m : map.entrySet()) {
            System.out.println(m.getKey() + " " + m.getValue());
        }
    }
}

出力結果:

HCL 100
DELL 200
IBM 300

ConcurrentHashMapの使用例

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ConcurrentHashMapExample {
    public static void main(String[] args) {
        // ConcurrentHashMapの作成
        Map<String, String> myMap = new ConcurrentHashMap<>();
        myMap.put("HCL", "1");
        myMap.put("DELL", "2");
        myMap.put("IBM", "3");

        // マップの内容を出力
        for (Map.Entry<String, String> m : myMap.entrySet()) {
            System.out.println(m.getKey() + " " + m.getValue());
        }
    }
}

出力結果:

HCL 1
DELL 2
IBM 3

まとめ

Hashtableは歴史の長いAPIですが、現在では新規コードでの使用は推奨されていません。マルチスレッド環境でMapが必要な場合は、細粒度ロックによる高いパフォーマンスを発揮するConcurrentHashMapを選択するのがベストプラクティスです。一方、シングルスレッド環境であれば、HashMapやLinkedHashMapで十分対応できます。用途に応じて適切な実装を選びましょう。

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

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

  2. tkinterとTkinterの違いとは?Pythonバージョン別の正しいインポート方法

    ローカルコンピュータにtkinterを導入する際には、OSの種類やアーキテクチャに応じて適切なコマンドを使い分ける必要があります。また、Windows環境でtkinterライブラリをインポートする方法も、Pythonのバージョンによって異なります。Python 2などの旧バージョンでは、次のコマンドでtkinterライブラリをインポートするのが一般的でした。from Tkinter import *一方、Python 3以降の環境では、次のように記述します。from tkinter import *Tkinterとtkinterの違い両者の唯一の違いは、先頭が大文字の「Tkinter」がPyt