ConcurrentHashMap Code Reading
Upcoming SlideShare
Loading in...5
×
 

ConcurrentHashMap Code Reading

on

  • 3,205 views

 

Statistics

Views

Total Views
3,205
Views on SlideShare
3,202
Embed Views
3

Actions

Likes
0
Downloads
7
Comments
0

3 Embeds 3

http://www.slideshare.net 1
http://b.hatena.ne.jp 1
http://www.slideee.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

ConcurrentHashMap Code Reading Presentation Transcript

  • 1. ConcurrentHashMap Code Reading 角田 直行 <kakuda@gmail.com>
  • 2. Agenda• 準備• Overview• 読む• まとめ
  • 3. 準備
  • 4. 準備するもの• Eclipse• ソース • ConcurrentHashMap.java • テストケース • JSR166TestCase.java • ConcurrentHashMapTest.java• ConcurrentHashMapに関する参照資料• 気合い
  • 5. ソースの取得場所• ConcurrentHashMap.javaはJDKより• テストケースはDoug Leaさんのサイトより http://gee.cs.oswego.edu/dl/concurrency-interest/
  • 6. 参照した資料• JavaDoc http://java.sun.com/javase/ja/6/docs/ja/api/java/util/concurrent/ ConcurrentHashMap.html• IBM developerWorks:優れたHashMapの構築 http://www.ibm.com/developerworks/jp/java/library/j-jtp08223/• ITアーキテクト J2SE 5.0の新機能 http://www.itarchitect.jp/technology_and_programming/-/24161-3.html• Servlet Gardern@はてな http://d.hatena.ne.jp/yokolet/20071005
  • 7. Overview
  • 8. Overview• Constants: 6つ• Field: 6つ• ユーティリティ: 2つ(hash(), segmentFor())• インナークラス: 2つ(HashEntry, Segment)• Public メソッド: 24コ(Constructorは5つ)• Iteratorサポート: 8つ• Serializationサポート: 2つ(writeObject(), readObject())
  • 9. 多分重要なトコ• Constants: 6つ• Field: 6つ• ユーティリティ: 2つ(hash(), segmentFor())• インナークラス: 2つ(HashEntry, Segment)• Public メソッド: 24コ(Constructorは5つ)• Iteratorサポート: 8つ• Serializationサポート: 2つ(writeObject(), readObject())
  • 10. 今回は割愛するトコ• Constants: 6つ• Field: 6つ• ユーティリティ: 2つ(hash(), segmentFor())• インナークラス: 2つ(HashEntry, Segment)• Public メソッド: 24コ(Constructorは5つ)• Iteratorサポート: 8つ• Serializationサポート: 2つ(writeObject(), readObject())
  • 11. 読む
  • 12. コンストラクタpublic ConcurrentHashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);}public ConcurrentHashMap(int initialCapacity) { this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);}public ConcurrentHashMap(int initialCapacity, float loadFactor) { this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);}
  • 13. コンストラクタ/** デフォルトの初期容量 */static final int DEFAULT_INITIAL_CAPACITY = 16;/** デフォルトの負荷係数 */static final float DEFAULT_LOAD_FACTOR = 0.75f;/** デフォルトの並行処理レベル */static final int DEFAULT_CONCURRENCY_LEVEL = 16;
  • 14. コンストラクタ/** 最大Segment数 1を16ビット分左にシフトしてるので65536 */static final int MAX_SEGMENTS = 1 << 16;...public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) { if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0) throw new IllegalArgumentException(); // 並行処理レベルが最大セグメント数を超えてはならない if (concurrencyLevel > MAX_SEGMENTS) concurrencyLevel = MAX_SEGMENTS; ...
  • 15. Segment数の決定/** どのSegmentにあるかを特定するためのマスク値 */final int segmentMask;/** どのSegmentにあるかを特定するためのシフト値 */final int segmentShift; // SegmentとHashエントリの最適な引数を見つける int sshift = 0; int ssize = 1; while (ssize < concurrencyLevel) { ++sshift; ssize <<= 1; } // currencyLevelが16(デフォルト)の時、sshiftは4、ssizeは16になる segmentShift = 32 - sshift; // 28(32は32bitのこと?) segmentMask = ssize - 1; // 15(0b0111) this.segments = Segment.newArray(ssize);
  • 16. Segmentの生成/** 最大容量 1を30ビット分左にシフトしてるので1073741824 */static final int MAXIMUM_CAPACITY = 1 << 30; // Segmentの初期容量の算出 if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; int c = initialCapacity / ssize; if (c * ssize < initialCapacity) ++c; int cap = 1; while (cap < c) cap <<= 1; for (int i = 0; i < this.segments.length; ++i) this.segments[i] = new Segment<K,V>(cap, loadFactor);}
  • 17. Segmentとは• ConcurrentHashMap.javaにて定義されて いるインナークラス • 1つのConcurrentHashMapインスタンス に複数(デフォルト16)のSegmentを持つ• ハッシュテーブルの特別バージョン• ReentrantLockのサブクラス
  • 18. Segmentのコンストラクタstatic final class Segment<K,V> extends ReentrantLock implements Serializable { ... transient int threshold; // 各SegmentにHashEntryの配列を保持 transient volatile HashEntry<K,V>[] table; ... Segment(int initialCapacity, float lf) { loadFactor = lf; setTable(HashEntry.<K,V>newArray(initialCapacity)); } ... void setTable(HashEntry<K,V>[] newTable) { threshold = (int)(newTable.length * loadFactor); table = newTable; }
  • 19. HashEntryとは• ConcurrentHashMap.javaにて定義されて いるインナークラス • 1つのSegmentインスタンスに1つ以上の HashEntryを持つ• フィールドにkey, hash値, value, next(次の HashEntry)を持つ • key, hash, nextはfinal
  • 20. HashEntrystatic final class HashEntry<K,V> { final K key; final int hash; volatile V value; final HashEntry<K,V> next; HashEntry(K key, int hash, HashEntry<K,V> next, V value) { this.key = key; this.hash = hash; this.next = next; this.value = value; } @SuppressWarnings("unchecked") static final <K,V> HashEntry<K,V>[] newArray(int i) { return new HashEntry[i]; }}
  • 21. Segment、HashEntryの構造
  • 22. Segment、HashEntryの構造 ConcurrentHashMap
  • 23. Segment、HashEntryの構造 Segment Segment ConcurrentHashMap ・ ・ ・ Segment
  • 24. Segment、HashEntryの構造 Hash Entry Segment Segment ConcurrentHashMap ・ ・ ・ Segment
  • 25. Segment、HashEntryの構造 Hash Entry Segment Hash Entry Segment ConcurrentHashMap ・ ・ ・ Segment
  • 26. Segment、HashEntryの構造 Hash Hash Entry Segment Entry Hash Entry Segment ConcurrentHashMap ・ ・ ・ Segment
  • 27. Segment、HashEntryの構造 Hash Hash Entry Segment Entry Hash Hash Entry Segment Entry ConcurrentHashMap ・ ・ ・ Segment
  • 28. Segment、HashEntryの構造 Hash Hash Hash Entry Segment Entry Entry Hash Hash Entry Segment Entry ConcurrentHashMap ・ ・ ・ Segment
  • 29. Segment、HashEntryの構造 Hash Hash Hash Entry Segment Entry Entry 実際のチェーン数は 1∼2個くらい Hash Hash Entry Segment Entry ConcurrentHashMap ・ ・ ・ Segment
  • 30. Segment、HashEntryの構造 Hash Hash Hash Entry Segment Entry Entry 実際のチェーン数は 1∼2個くらい Hash Hash Entry Segment Entry ConcurrentHashMap ・ ・ ・ Hash Entry Segment
  • 31. Segment、HashEntryの構造 Hash Hash Hash Entry Segment Entry Entry 実際のチェーン数は 1∼2個くらい Hash Hash Entry Segment Entry ConcurrentHashMap ・ ・ 全Segmentが埋まったらSegment ・ のサイズは2倍に拡張される Hash Entry Segment
  • 32. ConcurrentHashMap#getpublic V get(Object key) { // 与えられたハッシュ値を元にちゃんとしたハッシュ値を求める int hash = hash(key.hashCode()); // ハッシュ値に該当するセグメントを見つけSegment#getをcall return segmentFor(hash).get(key, hash);}
  • 33. 他の主要メソッドも 似たような処理 public boolean remove(Object key, Object value) { int hash = hash(key.hashCode());public boolean containsKey(Object key) { if (value == null) int hash = hash(key.hashCode()); return false; return segmentFor(hash).containsKey(key, hash); return segmentFor(hash).remove(key, hash, value) !=} null;public V put(K key, V value) { } if (value == null) public boolean replace(K key, V oldValue, V newValue) { throw new NullPointerException(); if (oldValue == null || newValue == null) int hash = hash(key.hashCode()); throw new NullPointerException(); return segmentFor(hash).put(key, hash, value, false); int hash = hash(key.hashCode());} return segmentFor(hash).replace(key, hash, oldValue,public V putIfAbsent(K key, V value) { newValue); if (value == null) } throw new NullPointerException(); public V replace(K key, V value) { int hash = hash(key.hashCode()); if (value == null) return segmentFor(hash).put(key, hash, value, true); throw new NullPointerException();} int hash = hash(key.hashCode()); return segmentFor(hash).replace(key, hash, value); }
  • 34. 他の主要メソッドも 似たような処理 public boolean remove(Object key, Object value) { int hash = hash(key.hashCode());public boolean containsKey(Object key) { if (value == null) int hash = hash(key.hashCode()); return false; return segmentFor(hash).containsKey(key, hash); return segmentFor(hash).remove(key, hash, value) !=} null;public V put(K key, V value) { } if (value == null) public boolean replace(K key, V oldValue, V newValue) { throw new NullPointerException(); if (oldValue == null || newValue == null) int hash = hash(key.hashCode()); throw new NullPointerException(); return segmentFor(hash).put(key, hash, value, false); int hash = hash(key.hashCode());} return segmentFor(hash).replace(key, hash, oldValue,public V putIfAbsent(K key, V value) { newValue); if (value == null) } throw new NullPointerException(); public V replace(K key, V value) { int hash = hash(key.hashCode()); if (value == null) return segmentFor(hash).put(key, hash, value, true); throw new NullPointerException();} int hash = hash(key.hashCode()); return segmentFor(hash).replace(key, hash, value); }
  • 35. ConcurrentHashMap#hash 何やっているかわかりません・・・orzprivate static int hash(int h) { // Spread bits to regularize both segment and index locations, // using variant of single-word Wang/Jenkins hash. h += (h << 15) ^ 0xffffcd7d; h ^= (h >>> 10); h += (h << 3); h ^= (h >>> 6); h += (h << 2) + (h << 14); return h ^ (h >>> 16);} HashMap#hashよりBetterな実装に置き換えてる http://www.concentric.net/ Ttwang/tech/inthash.htm が参考ソース?
  • 36. いいハッシュ値を返すと・・・ Segment Segment ConcurrentHashMap ・ ・ ・ Segment
  • 37. いいハッシュ値を返すと・・・ Segment(“1”, “a”) Segment PUT ConcurrentHashMap ・ ・ ・ Segment
  • 38. いいハッシュ値を返すと・・・ (“1”, “a”) Segment Segment ConcurrentHashMap ・ ・ ・ Segment
  • 39. いいハッシュ値を返すと・・・ (“1”, “a”) Segment(“2”, “b”) Segment PUT ConcurrentHashMap ・ ・ ・ Segment
  • 40. いいハッシュ値を返すと・・・ (“1”, “a”) Segment (“2”, “b”) Segment ConcurrentHashMap ・ ・ ・ Segment
  • 41. いいハッシュ値を返すと・・・ (“1”, “a”) Segment(“3”, “c”) (“2”, “b”) SegmentPUT ConcurrentHashMap ・ ・ ・ Segment
  • 42. いいハッシュ値を返すと・・・ (“1”, “a”) Segment (“2”, “b”) Segment ConcurrentHashMap ・ ・ ・ (“3”, “c”) Segment
  • 43. いいハッシュ値を返すと・・・ (“1”, “a”) Segment (“2”, “b”) Segmentちゃんとバラけてくれる! ConcurrentHashMap ・ ・ ・ (“3”, “c”) Segment
  • 44. 悪いハッシュ値を返すと・・・ Segment Segment ConcurrentHashMap ・ ・ ・ Segment
  • 45. 悪いハッシュ値を返すと・・・ Segment(“1”, “a”) Segment PUT ConcurrentHashMap ・ ・ ・ Segment
  • 46. 悪いハッシュ値を返すと・・・ (“1”, “a”) Segment Segment ConcurrentHashMap ・ ・ ・ Segment
  • 47. 悪いハッシュ値を返すと・・・ (“1”, “a”) Segment(“2”, “b”) Segment PUT ConcurrentHashMap ・ ・ ・ Segment
  • 48. 悪いハッシュ値を返すと・・・ (“1”, “a”) (“2”, Segment “b”) Segment ConcurrentHashMap ・ ・ ・ Segment
  • 49. 悪いハッシュ値を返すと・・・ (“1”, “a”) (“2”, Segment “b”)(“3”, “c”) SegmentPUT ConcurrentHashMap ・ ・ ・ Segment
  • 50. 悪いハッシュ値を返すと・・・ (“1”, “a”) (“2”, Segment “b”) (“3”, “c”) Segment ConcurrentHashMap ・ ・ ・ Segment
  • 51. 悪いハッシュ値を返すと・・・ (“1”, “a”) (“2”, Segment “b”) (“3”, “c”) Segment 偏ってしまい、 ConcurrentHashMap ・すごく効率が悪くなる! ・ ・ Segment
  • 52. Segment#getV get(Object key, int hash) { if (count != 0) { // read-volatile // hashに相当するHashEntryの要素を取り出す HashEntry<K,V> e = getFirst(hash); while (e != null) { if (e.hash == hash && key.equals(e.key)) { // HashEntryのハッシュ値とキーが両方とも合えば V v = e.value; if (v != null) return v; return readValueUnderLock(e); // recheck } e = e.next; } } return null;}
  • 53. Segment#containsKey 基本Segment#getと同じboolean containsKey(Object key, int hash) { if (count != 0) { // read-volatile HashEntry<K,V> e = getFirst(hash); while (e != null) { if (e.hash == hash && key.equals(e.key)) return true; e = e.next; } } return false;}
  • 54. Segment#containsValueboolean containsValue(Object value) { if (count != 0) { // read-volatile HashEntry<K,V>[] tab = table; // 変化する恐れがあるので作業用に置いてる? int len = tab.length; for (int i = 0 ; i < len; i++) { for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) { V v = e.value; if (v == null) // recheck v = readValueUnderLock(e); // 理屈上こういうことがありうるらしい if (value.equals(v)) return true; } } } return false;}
  • 55. Segment#putV put(K key, int hash, V value, boolean onlyIfAbsent) { lock(); // HashEntryの更新系(put, remove, replace...)はロックが必要 try { int c = count; if (c++ > threshold) // ensure capacity rehash(); // サイズがしきい値を超えたら各要素のハッシュ値を再計算 HashEntry<K,V>[] tab = table; int index = hash & (tab.length - 1); HashEntry<K,V> first = tab[index]; HashEntry<K,V> e = first; while (e != null && (e.hash != hash || !key.equals(e.key))) // どういうケース? e = e.next;...
  • 56. Segment#put V oldValue; if (e != null) { oldValue = e.value; if (! onlyIfAbsent) e.value = value; } else { // 基本はここを通る oldValue = null; ++modCount; // HashEntryの構造が変更された回数を増やす tab[index] = new HashEntry<K,V>(key, hash, first, value); count = c; // write-volatile } return oldValue; } finally { unlock(); }}
  • 57. Segment#remove 前半部分はSegment#putと大体同じV remove(Object key, int hash, Object value) { lock(); try { int c = count - 1; // サイズを1つ減らす HashEntry<K,V>[] tab = table; int index = hash & (tab.length - 1); HashEntry<K,V> first = tab[index]; HashEntry<K,V> e = first; while (e != null && (e.hash != hash || !key.equals(e.key))) e = e.next; V oldValue = null;...
  • 58. Segment#remove if (e != null) { V v = e.value; if (value == null || value.equals(v)) { oldValue = v; ++modCount; HashEntry<K,V> newFirst = e.next; for (HashEntry<K,V> p = first; p != e; p = p.next) newFirst = new HashEntry<K,V>(p.key, p.hash, newFirst, p.value); tab[index] = newFirst; count = c; // write-volatile } } return oldValue; } finally { unlock(); }}
  • 59. Segment#remove if (e != null) { V v = e.value; if (value == null || value.equals(v)) { oldValue = v; ++modCount; HashEntry<K,V> newFirst = e.next; for (HashEntry<K,V> p = first; p != e; p = p.next) newFirst = new HashEntry<K,V>(p.key, p.hash, newFirst, p.value); tab[index] = newFirst; count = c; // write-volatile } } return oldValue; } finally { unlock(); }}
  • 60. Segment#remove• HashEntryにはnextという次の要素を表す フィールドがある• removeが行われるとnextの付け替えが発生 する• nextフィールドはfinalなので削除した要素よ り前を作り直さなければならない
  • 61. A B C D E SegmentNext = B Next = C Next = D Next = E Next = null
  • 62. A B C D E SegmentNext = B Next = C Next = D Next = E Next = null remove(“C”)
  • 63. A B D E SegmentNext = B Next = C Next = E Next = null
  • 64. Nextがfinalなので A B Dに変更できない!D E SegmentNext = B Next = C Next = E Next = null
  • 65. Nextがfinalなので A B Dに変更できない!D E SegmentNext = B Next = C Next = E Next = null AとBは作り直し
  • 66. Segment#rehash put時にサイズがcapacityを超えた時に発生void rehash() { HashEntry<K,V>[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity >= MAXIMUM_CAPACITY) return; /* * Reclassify nodes in each list to new Map. Because we are * using power-of-two expansion, the elements from each bin * must either stay at same index, or move with a power of two * offset. We eliminate unnecessary node creation by catching...
  • 67. コメントの超意訳• 各リストのノードを新しいMapに再分類する。2つの強力 な拡張(SegmentとHashEntry)を使っているため、同じ indexを保つか2つのoffsetを同時に移動させなければなら ない。nextフィールドは変わらないので、古いノードは再 利用でき不必要なノードを作らなくてすむ。統計的に、デ フォルトのthresholdだとテーブルを2倍にする時にクロー ンする必要があるのは約1/6。置き換わる古いノードは readerスレッドがすぐにテーブルを走査することで参照さ れなくなりGC対象となる。
  • 68. Segment#clearvoid clear() { if (count != 0) { lock(); try { HashEntry<K,V>[] tab = table; for (int i = 0; i < tab.length ; i++) tab[i] = null; ++modCount; count = 0; // write-volatile } finally { unlock(); } }}
  • 69. Segment#replaceV replace(K key, int hash, V newValue) { lock(); try { HashEntry<K,V> e = getFirst(hash); while (e != null && (e.hash != hash || !key.equals(e.key))) e = e.next; V oldValue = null; if (e != null) { oldValue = e.value; e.value = newValue; } return oldValue; } finally { unlock(); }}
  • 70. Segment#replace その2boolean replace(K key, int hash, V oldValue, V newValue) { lock(); try { HashEntry<K,V> e = getFirst(hash); while (e != null && (e.hash != hash || !key.equals(e.key))) e = e.next; boolean replaced = false; if (e != null && oldValue.equals(e.value)) { replaced = true; e.value = newValue; } return replaced; } finally { unlock(); }}
  • 71. ConcurrentHashMap#isEmptypublic boolean isEmpty() { final Segment<K,V>[] segments = this.segments; int[] mc = new int[segments.length]; int mcsum = 0; for (int i = 0; i < segments.length; ++i) { if (segments[i].count != 0) return false; else // 全segmentのサイズが0の時、それぞれの変更回数の和を計算する mcsum += mc[i] = segments[i].modCount; }...
  • 72. ConcurrentHashMap#isEmpty if (mcsum != 0) { // 何かしらの変更 (ABA問題) があった場合 for (int i = 0; i < segments.length; ++i) { if (segments[i].count != 0 || mc[i] != segments[i].modCount) return false; } } return true;}
  • 73. isEmptyのコメント超意訳• いつの時点でもテーブルが空にならなかった場合、ある segmentの一要素が追加され別で走査中に削除されるとい うABA問題(「Java並行処理プログラミング」15章参照)を 避けるために各segmentのmodCountを追跡する。他に ABA問題の影響を受ける可能性があるsize()や containsValue()メソッドでも同様にmodCountを使ってい る。
  • 74. ConcurrentHashMap#size• まずはロック無しで2回までトライする • 数えている間に、別で変更処理が行われた らやり直す• 2回とも邪魔されてしまったら全Segmentに ロックをかけて数える
  • 75. ConcurrentHashMap#size/** size()とcontainsValue()で使われる */static final int RETRIES_BEFORE_LOCK = 2; public int size() { final Segment<K,V>[] segments = this.segments; long sum = 0; long check = 0; int[] mc = new int[segments.length]; // Try a few times to get accurate count. On failure due to // continuous async changes in table, resort to locking. for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { check = 0; sum = 0; int mcsum = 0; ...
  • 76. ConcurrentHashMap#size for (int i = 0; i < segments.length; ++i) { sum += segments[i].count; mcsum += mc[i] = segments[i].modCount; } if (mcsum != 0) { // 初期状態から変更が行われた for (int i = 0; i < segments.length; ++i) { check += segments[i].count; if (mc[i] != segments[i].modCount) { // 変更された check = -1; // force retry(「Java並行処理プログラミング」P269) break; } } } if (check == sum) break;}
  • 77. ConcurrentHashMap#size if (check != sum) { // Resort to locking all segments sum = 0; for (int i = 0; i < segments.length; ++i) //全Segmentをロック segments[i].lock(); for (int i = 0; i < segments.length; ++i) sum += segments[i].count; for (int i = 0; i < segments.length; ++i) segments[i].unlock(); } if (sum > Integer.MAX_VALUE) return Integer.MAX_VALUE; else return (int)sum;}
  • 78. ConcurrentHashMap#containsValue ConcurrentHashMap#sizeと大体同じpublic boolean containsValue(Object value) { if (value == null) throw new NullPointerException(); // See explanation of modCount use above final Segment<K,V>[] segments = this.segments; int[] mc = new int[segments.length]; // Try a few times without locking for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) { int sum = 0; int mcsum = 0;...
  • 79. ConcurrentHashMap#containsValue for (int i = 0; i < segments.length; ++i) { int c = segments[i].count; // メモリを同期化 mcsum += mc[i] = segments[i].modCount; if (segments[i].containsValue(value)) return true; } boolean cleanSweep = true; if (mcsum != 0) { // 初期状態から変更された for (int i = 0; i < segments.length; ++i) { int c = segments[i].count; // メモリを同期化 if (mc[i] != segments[i].modCount) { // 変更されたのでやり直し cleanSweep = false; break; } } } if (cleanSweep) return false;}
  • 80. ConcurrentHashMap#containsValue // Resort to locking all segments for (int i = 0; i < segments.length; ++i) segments[i].lock(); boolean found = false; try { for (int i = 0; i < segments.length; ++i) { if (segments[i].containsValue(value)) { // Segment#containsValue found = true; break; } } } finally { for (int i = 0; i < segments.length; ++i) segments[i].unlock(); } return found;}
  • 81. まとめ
  • 82. まとめ• ConcurrentHashMapは、Segmentと HashEntryというデータ構造が肝• 高速化のために色んなことをやってる • finalでread時はロックしないように • hash値計算でちゃんとばらけさせる • ロック処理を最小限に抑える
  • 83. ちなみに• ConcurrentHashMapより速い NonBlockingHashMapというのがある• Azul SystemsのCliff Click氏作 (DN$&6;OK)$P$&$QA/R$5F*. :L$@8M+0 :D$@8M+0 77768)*+.-./01.6591 ! ! &< HIE"" &< JKDE"" & & DE9F.G.05 DE9F.G.05 HIE>< :< :< : JKDE>< : < < HI JKD : & ! ; < = > ? : & ! ; < = > ? @AB08C. @AB08C. $ #$$$$%&!$()*+$,-./01.2$3456 !"
  • 84. 詳しく知りたい人は• JavaOne資料「A Lock-Free Hash Table」 http://www.azulsystems.com/events/javaone_2007/2007_LockFreeHash.pdf• Blog記事「A Non-Blocking HashTable」 http://blogs.azulsystems.com/cliff/2007/03/a_nonblocking_h.html• Highly Scalable Java http://sourceforge.net/projects/high-scale-lib
  • 85. ご清聴ありがとう ございました!