HashMapからConcurrentHashMapへの移行

Similar documents
Java の ConcurrentHashMap における同期化 バッドケースとその対処法 2013 年 9 月湊隆行 1. はじめに表 1.1 に示すように Java の Collections Framework には 3 つの世代があります バージョン 1.0 から存在するレガシー API バ

ファイナライザを理解する ~ ファイナライザに起因するトラブルを避けるために ~ 2013 年 11 月 25 日 橋口雅史 Java アプリケーションでファイナライザ (finalize() メソッド ) を使用したことがあるプログラマーは多いと思います しかし ファイナライザの仕組みや注意点につ

Microsoft PowerPoint ppt

Prog1_15th

V8.1新規機能紹介記事

PowerPoint プレゼンテーション

Java知識テスト問題

Microsoft PowerPoint - Pro110111

intra-mart Accel Platform — IM-Repository拡張プログラミングガイド   初版  

intra-mart Accel Platform — IM-BloomMaker プログラミングガイド   初版  

Exam : 1z1-809-JPN Title : Java SE 8 Programmer II Vendor : Oracle Version : DEMO Get Latest & Valid 1z1-809-JPN Exam's Question and Answers 1 from Ac

ただし 無作為にスレッドを複数実行すると 結果不正やデッドロックが起きる可能性がある 複数のスレッド ( マルチスレッド ) を安全に実行する ( スレッドセーフにする ) ためには 同期処理を用いるこ とが必要になる 同期処理は 予約語 synchronized で行うことができる ここでは sy

第 3 回 Java 講座 今回の内容 今週の Java 講座はコレクション 拡張 for 文, ガベージコレクションについて扱う. 今週の Java 講座は一番内容が薄いも のになるだろう. コレクション コレクションとは大きさが決まっていない配列だと考えればよい. コレクションには List 先

PowerPoint プレゼンテーション

Javaと マルチスレッド

開発・運用時のガイド JDK8への移行に伴う留意点 [UNIX]

デザインパターン第一章「生成《

Microsoft PowerPoint - FormsUpgrade_Tune.ppt

Javaセキュアコーディングセミナー東京 第3回 入出力(File, Stream)と例外時の動作 演習解説

JavaプログラミングⅠ

Javaの作成の前に

Oracle Cloud Adapter for Oracle RightNow Cloud Service

Developer Camp

GEC-Java

スライド 1

JUnit 概要 2015/4/16 版今泉俊幸 2015 bbreak Systems 1

メソッドのまとめ

JAVA とテンプレート

メディプロ1 Javaプログラミング補足資料.ppt

DumpCollection IT Exam Training online / Bootcamp PDF and Testing Engine, study and practice

.NETプログラマー早期育成ドリル ~VB編 付録 文法早見表~

Pervasive PSQL v11 のベンチマーク パフォーマンスの結果

Prog1_10th

Microsoft PowerPoint Java基本技術PrintOut.ppt [互換モード]

Program Design (プログラム設計)

21 章のお話

JAVA入門

Insert your Title here

Week 1 理解度確認クイズ解答 解説 問題 1 (4 2 点 =8 点 ) 以下の各問いに答えよ 問題 bit 版の Windows8.1 に Java をインストールする時 必要なパッケージはどれか 但し Java のコンパイルができる環境をインストールするものとする 1. jdk

** 平成 16 年度 FE 午後問題 Java** 示現塾プロジェクトマネージャ テクニカルエンジニア ( ネットワーク ) など各種セミナーを開催中!! 開催日 受講料 カリキュラム等 詳しくは 今すぐアクセス!! 平成 16

Javaセキュアコーディングセミナー2013東京第1回 演習の解説


IronPython による柔軟なゲーム開発 筑波大学 AmusementCreators

Sort-of-List-Map(A)

JS2-14 マルチコアCPU時代の Javaプログラミング

ObjectPartner Pro

解答上の注意 1 解答は 解答 紙の問題番号に対応した解答欄にマークしなさい 2 選択肢は 問ごとに 意されています 問 1の選択肢は 問 2で使 しません 3 選択肢は量が多いため 探しやすさの観点よりグループ分けされています グループ分けに合わせて解答欄が区切られていますが 横 1 列で問題 1

パフォーマンス徹底比較 Seasar2 vs Spring 2006/04/12 株式会社電通国際情報サービスひがやすを株式会社アークシステム本間宏崇 Copyright the Seasar Foundation and the others all rights reserved.

FW APIServer 設定ガイド Version 年 2 月 3 日富士通株式会社 i All Right Reserved, Copyright FUJITSU LIMITED

Microsoft PowerPoint - ●SWIM_ _INET掲載用.pptx

ダンプ取得機能強化サポートオプション Enterprise Edition

第1章 ビジュアルプログラミング入門

JAVA入門

WebOTXプロファイラを使用したメモリリーク調査方法

プログラミング基礎I(再)

富士通製プラットフォーム 「PRIMEPOWER/PRIMERGY」及び、富士通製ミドルウェア 「Interstage」とVantage Analyzer 動作検証完了報告書

Microsoft PowerPoint - OSS運用管理勉強会資料_ a.pptx

intra-mart Accel Platform — IM-LogicDesigner拡張プログラミングガイド   初版  

(Microsoft PowerPoint - \223\306\217KJAVA\221\346\202R\224\ ppt)

— intra-mart Accel Platform IM-LogicDesigner拡張プログラミングガイド   初版   None

CashDrawer ライブラリ API 仕様書 2014/07/09 CashDrawer ライブラリ API 仕様書 Rev / 10

9.3 同期 共有データへの読み書きの同期 複数のスレッドから共有データを読み書きするときに発生する問題について 一つのフィールドに対して複数のスレッドが同時にアクセスする可能性がある場合 その順番によっては整合性が保てなくなる可能性があるので スレッドの制御フローが独立していては困ることがある 次

Brekeke PBX - Version 2.1 ARSプラグイン開発ガイド

1. 開発ツールの概要 1.1 OSS の開発ツール本書では OSS( オープンソースソフトウェア ) の開発ツールを使用します 一般に OSS は営利企業ではない特定のグループが開発するソフトウェアで ソースコードが公開されており無償で使用できます OSS は誰でも開発に参加できますが 大規模な

POSIXスレッド

Prog1_6th

intra-mart Accel Platform — イベントナビゲータ 開発ガイド   初版   None

第2回講義

Microsoft Word - A04 - Configuring Launch In Context_jp-ReviewedandCorrected a.doc

文字列操作と正規表現

PowerPoint Presentation

PowerPoint プレゼンテーション

データ構造とアルゴリズム論

Microsoft PowerPoint - OOP.pptx

参考 - メインスレッドは JVM によって自動的に起動されるため 起動するコードを書く必要 はありません 今まで例題 演習で作成してきたプログラムは全てメインメソッドにて 動作している シングルスレッドです マルチスレッドマルチスレッドとは名前のとおり複数のスレッドと言う意味です マルチスレッドは

storage-sdk-Java

memcached 方式 (No Replication) 認証情報は ログインした tomcat と設定された各 memcached サーバーに認証情報を分割し振り分けて保管する memcached の方系がダウンした場合は ログインしたことのあるサーバーへのアクセスでは tomcat に認証情報

Javaセキュアコーディングセミナー東京 第2回 数値データの取扱いと入力値の検証 演習解説

問題1 以下に示すプログラムは、次の処理をするプログラムである

2

第 1 章 Java 言語について ( オブジェクト指向, 変数の扱い方, 繰り返し条件と条件分岐 ) Java 言語の概要とオブジェクト指向, 変数の扱い方, 繰り返し条件と条件分岐について理解し, プログラム作成を行う 1.1 Java 言語の概要 JAVA は Sun Microsystems

TopSE並行システム はじめに

PowerPoint プレゼンテーション

グラフの探索 JAVA での実装

5 継承とは クラス図 98 7 参照の自動型変換 参照の自動型変換 クラス図の見方 クラス図の書き方 継承 継承してクラスを作る インスタンスの初期化 継承の効果を確認する

intra-mart Accel Platform

JavaプログラミングⅠ

た場合クラスを用いて 以下のように書くことが出来る ( 教科書 p.270) プログラム例 2( ソースファイル名 :Chap08/AccountTester.java) // 銀行口座クラスとそれをテストするクラス第 1 版 // 銀行口座クラス class Account String name

(Microsoft PowerPoint - ClickFramework.ppt [\214\335\212\267\203\202\201[\203h])

IBM i ユーザーの課題 モバイルや IOT に対応した新しい開発案件への対応 RPG COBOL など既存アプリのメンテナンス 要員の確保 属人化しない運用 管理体制 2

JavaプログラミングⅠ

検証事例 富士通株式会社

CodeRecorderでカバレッジ

11 ソフトウェア工学 Software Engineering デザインパターン DESIGN PATTERNS デザインパターンとは? デザインパターン 過去のソフトウェア設計者が生み出したオブジェクト指向設計に関して, ノウハウを蓄積し 名前をつけ 再利用しやすいようにカタログ化したもの 各デ

IT プロジェクト

IM-SecureSignOn

表示の更新もそういた作業のひとつに当たる スレッドの使用アニメーション アニメーションやシミュレーションなどは画面の更新が一定のタイミングで行われていく この連続した画面の更新をスレッドを利用して行う しかし paint() メソッドを直接呼び出して表示を更新することはできない その理由

Prog2_9th

intra-mart Accel Platform — イベントナビゲータ 開発ガイド   初版  

スライド 1

Transcription:

HashMap から ConcurrentHashMap への移行 レガシー アプリケーションにおける注意点 2012 年 1 月 4 日橋口雅史 1. はじめにアプリケーションでは キーと値のマッピングが多用されます 例えば ユーザー名 というキーにユーザーの 情報 をマッピングするといった用途で java.util.map インタフェースは広く使われています 特に ハッシュテーブルに基づいて高速にマップを検索 更新できる java.util.hashmap クラスは 様々なアプリケーションでよく使われています HashMap クラスの同期化は プログラマーが考慮する必要があります 残念ながら 正しく HashMap クラスが使われていないアプリケーションは数多く存在します そして 同期処理の誤りが原因で発生するトラブルは原因究明が難しく システム運用者を悩ませてきました 本書では HashMap を java.util.concurrent.concurrenthashmap に置き換えてシステムを安定稼働させるアイデアを紹介します 後述しますが ConcurrentHashMap は安全に使える高速なハッシュテーブル実装です 2. HashMapが引き起こすトラブル API 仕様に明記されているように HashMap クラスは同期化されません 複数のスレッドが並行して HashMap にアクセスし それらのスレッドの少なくともひとつが構造的にマップを変更する場合には 外部で同期をとる必要があります 適切な同期処理を実装しない場合 ハッシュテーブルの破壊や無限ループ メモリリークといった深刻な問題を引き起こすことがあります 例えば ある企業の情報システムでは 原因不明のメモリリークによるスローダウンが発生していました また メモリがリークしつづけた結果 最終的には OutOfMemoryError によるシステムダウンを引き起こしていました 事象はある日突然発生するため 確実に再現させられず 原因を特定するのが非常に困難でした 5 ヶ月間の調査の結果 システムを構成するアプリケーションが使用する HashMap のデータ構造が 破壊されていたことが分かりました 破壊の理由は HashMap の同期処理の誤りでした データ構造が破壊されたことにより テーブルを正しく更新できず メモリリーク発生に繋がっていたことが分かりました たった 1 行の同期処理の誤りが 何ヶ月も続くトラブルを引き起こしていたのです また 原因が判明するまでのあいだ 担当者は常にシステムを監視する必要があり 多大なコストを払う結果となりました 3. 安全な Hashtableと 使い方が難しい HashMap ハッシュテーブルを実装するクラスとしては Java の誕生当初から java.util.hashtable が存在します 1

Hashtable のほとんどのメソッドには synchronized 修飾子が指定されているため 外部で同期を取らなくとも 複数のスレッドによる並行アクセスが理由でハッシュテーブルが破壊されることはありません ただ メソッドに synchronized 修飾子が指定されているため ハッシュテーブルにアクセスするたびに同期処理が走ります 同期処理は実行コストが高いため性能に影響します そこで 性能を重視する多くのプログラマーは Hashtable ではなく HashMap を使ってきました そして 同期処理の工夫によって 性能上の利点とアプリケーションの安全な動作を両立させようとしてきました しかし 冒頭で述べたように 実際には少なくないバグが混入し 思いがけない動作を引き起こしてシステム管理者を悩ませ続けています このように 安全な Hashtable と 使い方が難しい HashMap のどちらを使うべきか 多くのプログラマーが選択を迫られてきたのです 4. 新しい HashMap の登場 J2SE 5.0 で導入された ConcurrentHashMap クラスは 安全性に関する Hashtable の特長と 性能に関する HashMap の利点を兼ね備えています 図 1は Hashtableにアクセスするアプリケーションスレッドの挙動を模式化したものです Hashtable にアクセスできるスレッドは常に 1 個であり それ以外のスレッドはそのアクセスが終わるまで待たされます 図 1 Hashtable へのアクセス アプリケーションスレッド 同じテーブルへのアクセス要求 テーブルに同時にアクセスできるスレッドは 1 個だけです そのスレッドがアクセスしているあいだ ほかのスレッドは待たされます 動作中 アクセス中 待ち状態 図 2は HashMapにアクセスするアプリケーションスレッドを表したものです どのスレッドも 自由に HashMapにアクセスできます そのため HashMapへのアクセスを適切に同期化していないアプリケーションはテーブルを破壊する恐れがあります 2

図 2 HashMap へのアクセス アプリケーションスレッド 同じテーブルへのアクセス要求 あるスレッドがテーブルにアクセスしているあいだも ほかのスレッドはテーブルにアクセスできます そのため 適切に同期化していないアプリケーションでは テーブルが破壊されることがあります 動作中 アクセス中 待ち状態 ConcurrentHashMap クラスは 機能仕様は Hashtable と同じでありながら アクセスのたびにロックするようなことがありません 通常は複数のスレッドが同時にアクセスできます 同時にアクセスするとテーブルが破壊されるような場合には 自動的に同期化します そのときの待ち時間は 非常に短くなるよう実装されています 図 3 ConcurrentHashMap へのアクセス アプリケーションスレッド 同じテーブルへのアクセス要求 多くの場合は複数のスレッドが同時にアクセスできます その際 テーブルが壊れることはありません アクセスを待たされることもありますが その時間は非常に短くなっています 動作中 アクセス中 待ち状態 そこで ConcurrentHashMap の性能をプログラムで検証してみます 使用したプログラムは 100,000 個の Integer オブジェクトからランダムに選んだものをキーとして get メソッドでマップに問い合わせます マップにエントリーが存在しない場合は put メソッドを呼び出してそのキーに対する値を登録します 各スレッドがこれを 1,000,000 回繰り返し 各スレッドの実行時間を合計して比較します Linux 64bit (Intel64) の環境で Java SE 6 を使って調べました 表 1 から分かるように スレッド数が多くなるにつれて実行時間の差が大きくなっていきます 3

ConcurrentHashMapを使う場合 同じマップにアクセスするスレッド数が増えても大幅な性能低下を示すことはありません 今回使用したテストプログラムは get と put の両方を呼び出すため HashMap との単純な比較はできませんでした しかし HashMap にアクセスするときに同期処理を実行するようなプログラムでは Hashtable と同様の結果を示すものと考えられます 表 1 性能比較 ( 単位はミリ秒 ) スレッド数 Hashtable ConcurrentHashMap 2 2313 3894 4 9316 3369 8 41925 13846 16 144271 47648 32 614624 184420 64 2411180 726194 図 4 性能比較のグラフ 処理時間 [ 秒 ] 3000000 2500000 2000000 1500000 1000000 500000 0 2 4 8 16 32 64 スレッド数 Hashtable ConcurrentHashMap このように ConcurrentHashMap は性能上の利点を持っています また 機能仕様は Hashtable と同じなので Hashtable と相互に置き換え可能です すなわち レガシーなコードを含む Java アプリケーションは Java ランタイムをバージョンアップする機会に Hashtable から ConcurrentHashMap への置き換えを検討する価値があります しかし Concurrent"HashMap" という名前のクラスでありながら HashMap から ConcurrentHashMap への置き換えは慎重に行う必要があります 5. HashMapからConcurrentHashMapへの置き換え HashMap を ConcurrentHashMap に置き換える場合は ふたつの点について考慮する必要があります 同期処理の見直し HashMap を使用するプログラムには すでに同期処理が実装されているかもしれません その場合 実装されている同期処理を修正しなければ ConcurrentHashMap の性能上の利点が活かされません 4

java.util.collections.synchronizedmap() で HashMap に対応する同期マップを生成して使用している場合は Collections.synchronizedMap() の生成処理を ConcurrentHashMap に置き換えるだけで十分です (HashMap へのアクセス時に 明示的な同期処理を実装していないだろうからです ) Collections.synchronizedMap() を使わず 独自に同期処理を実装している場合は HashMap に関するすべての同期処理を見直す必要があります ( 不要な同期処理を削除する必要があります ) ただし 仮に不要な同期処理が残っていたとしても 万が一の場合にハッシュテーブルの破壊を防げる という点から ConcurrentHashMap を使う価値はあります nullの扱い HashMap はエントリーのキーや値に null を使用できますが ConcurrentHashMap では使用できません 例えば キーに対する値が存在しない ことを示すため その値を null で表現したいプログラムがあるとします HashMap は値が null のエントリーを扱えます しかし ConcurrentHashMap に対して値が null のエントリーを登録しようとすると NullPointerException が発生します つまり 既存のプログラムで使っている HashMap を単純に ConcurrentHashMap に置き換えると 新たな問題 ( 例外の発生 ) を引き起こす恐れがあるということです ConcurrentHashMap クラスの次のメソッドは キーや値が null の場合に NullPointerException をスローします つまり HashMap を ConcurrentHashMap に置き換える前にこれらのメソッドの使用箇所を調べ上げ キーや値に null が使われることがないかどうか確認する必要があります get() containskey() containsvalue() contains() put() putifabsent() remove() replace() しかし 数多く存在する HashMap すべてについて確認するとなると 膨大な労力を必要とします そこで ConcurrentHashMap のラッパーとなるクラスを作成してその労力を軽減するアイデアを紹介します 例えば 次のように get() や put() などの NullPointerException をスローするメソッドをラップし ConcurrentHashMap のメソッドの引数に直接 null を与えないようにします 図 5 ConcurrentHashMap をラップする例 5

public class WrappedConcurrentHashMap implements Map { private static final Object NullObject = new Object(); private ConcurrentHashMap m = new ConcurrentHashMap(); public Object get(object key) { if (key == null) { key = NullObject; Object o = m.get(key); if (o == NullObject) { o = null; return o; そのようなラッパークラスを HashMap の代わりに使うことで NullPointerException を発生することなく HashMap を ConcurrentHashMap に置き換えられます 6. まとめこれから作る新しいプログラムは ConcurrentHashMap の使用を検討するべきです 複数のスレッドでハッシュテーブルを操作するアプリケーションにおいて 最適なパフォーマンスを得ることができるでしょう しかし もっと重要なことは 古くから存在するレガシー アプリケーションへの適用を検討することです HashMap の同期処理を誤ったために システム稼動後何年も経って問題が表面化する事例が発生しています これは ハードウェアが高性能化 ( マルチプロセッサ化 マルチコア化 ) するにしたがって アプリケーションのスレッドが並列に処理されることが増えてきていることが一因です ( アプリケーションを変更せず ミドルウェア OS やハードウェアだけを更新する場合に顕著です ) レガシーなアプリケーションを新しいシステムに移行する際は HashMap の使用箇所を点検して ConcurrentHashMap への置き換えを検討してください スレッドセーフの実現と性能向上を果たせる可能性があります HashMap を ConcurrentHashMap で置き換えるには 既存の同期処理を確認して不要なものを削除し NullPointerException に対処することが必要です ソースコードの修正が必要ですが スレッドセーフな挙動とスケーラビリティを得られるため ConcurrentHashMap に置き換える価値は十分あります 6

参考文献 Java 2 Platform Standard Edition 5.0 API Specification http://docs.oracle.com/javase/1.5.0/docs/api/ Java Platform, Standard Edition 6 API Specification http://docs.oracle.com/javase/6/docs/api/ Java Platform, Standard Edition 7 API Specification http://docs.oracle.com/javase/7/docs/api/ 7