Effective Javaによると
Effective Java 第3版の項目81 "waitとnotifyよりも並行処理ユーティリティを選ぶ"によるとConcurrentHashMap.putIfAbsentをそのまま使うよりも、public static String intern(String s) { String previousValue = map.putIfAbsent(s, s); return previousValue == null ? s : previousValue; }
一度ConcurrentHashMap.getで要素の存在を確認してからputIfAbsentを呼び出したほうが、高速化するというテクニックが出てくる。
public static String intern(String s) { String result = map.get(s); if (result == null) { result = map.putIfAbsent(s, s); if (result == null) result = s; } return result; }
普通に考えると
項番81は本件が主題なのではなく、少し触れられている程度の話なのだけれど、ConcurrentHashMap.getのみであれば同期操作が発生しないためだろう。そう考えると、ifの条件が成立する可能性が高い場合は、このテクニックを使うほうが速そうだし、逆の場合はかえって遅くなりそうな気がする。
完全に定数であれば、要素を追加して、Unmodifiableにした後は、同期する必要もなくgetするだけなので、このテクニックを使う必要はなさそう。
実際には一度計算したものを再計算したくないような場面で、キャッシュとしてConcurrentHashMapを使うときに役立つのかな。
ただし、マップに要素が存在しても値がnullの場合はifの条件が成立しないため、結局かえって遅くなるパターンになりそう。 こういう使い方はあまりないと思うけど。
ConcurrentHashMapとHashMapの非互換性
...と思ったんだけど、実際にConcurrentHashMapにnullの値を入れようとしたら、NullPointerExceptionが発生してしまった。ConcurrentHashMapのAPI仕様を確認すると確かに次のように書いてある。
Hashtableと同様に(HashMapとは異なる)、このクラスは、キーまたは値としてnullが使用されることを許可しません。
うーん、これだと最初HashMapを使っていて、後からConcurrentHashMapに変えた場合に困ったことになってしまう可能性がある。
キーはともかく値としてもMapにnullを入れるデザインは最初からしないほうがいいってことかな。
0 件のコメント:
コメントを投稿