ConcurrentHashMapのについて話をする方法スレッドセーフを確保することです
私たちは、ConcurrentHashMapのを知っている(1.8)同時コレクションフレームワークを使用すると、操作のソースを見るために得るとき、あなたは操作は、このブログで議論の問題で任意のロックを、追加されていない完全な取得ができますスレッドセーフである - なぜそれをあなたはそれをロックする必要はありませんか?
はじめのConcurrentHashMap
JDK1.8はHashEntryを複数備え、JDK1.7バージョンロック粒度がセグメントに基づいて、減速ロック粒度を達成するため、ロック粒度はJDK1.8 HashEntry(ヘッドノード)のデータ構造のJDK1.8バージョンはよりになることです小型化、実装の複雑さもJDK1を増加させるので、単純なは、同期を同期するために使用されているため、操作が、より明確で、滑らかなことなので、コンセプトはセグメントにロックを必要としないこと、不要セグメントは、このデータ構造は、ありません長鎖トラバーサルの長さに基づいて、リストの使用を最適化するために0.8赤黒木は、非常に長いプロセスであり、赤黒ツリートラバーサルの効率が最高のパートナーを形成する代わりに、所定の閾値のリストを、高速です。
操作ソースを取得
-
それは最初のノードに戻りに沿ったものである場合は、最初に、インデックステーブルの位置を見つけるために、ハッシュ値を計算します
-
あなたは、時間の拡張を持っている場合は、findメソッドは、ノード、マッチリターンの拡大と外観ですForwardingNodeノード兆候を呼び出します
-
上記のない出会いを行い、それはそれ以外の場合はnullを返し、最終的に、ノード、試合のリターンを横断するダウンしています
[Javaの]
プレーンテキストビュー
コードをコピー
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
揮発デビュー
可視性のために、Javaは整然とした、視認性を確保するために揮発性のキーワードを提供します。しかし、それは原子性を保証するものではありません。
普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。volatile关键字对于基本类型的修改可以在随后对多个线程的读保持一致,但是对于引用类型如数组,实体bean,仅仅保证引用的可见性,但并不保证引用内容的可见性。。禁止进行指令重排序。背景:为了提高处理速度,处理器不直接和内存进行通信,而是先将系统内存的数据读到内部缓存(L1,L2或其他)后再进行操作,但操作完不知道何时会写到内存。如果对声明了volatile的变量进行写操作,JVM就会向处理器发送一条指令,将这个变量所在缓存行的数据写回到系统内存。但是,就算写回到内存,如果其他处理器缓存的值还是旧的,再执行计算操作就会有问题。在多处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一致性协议,当某个CPU在写数据时,如果发现操作的变量是共享变量,则会通知其他CPU告知该变量的缓存行是无效的,因此其他CPU在读取该变量时,发现其无效会重新从主存中加载数据。
总结下来:
第一:使用volatile关键字会强制将修改的值立即写入主存;
第二:使用volatile关键字的话,当线程2进行修改时,会导致线程1的工作内存中缓存变量的缓存行无效(反映到硬件层的话,就是CPU的L1或者L2缓存中对应的缓存行无效);
第三:由于线程1的工作内存中缓存变量的缓存行无效,所以线程1再次读取变量的值时会去主存读取。
是加在数组上的volatile吗?
[Java]
纯文本查看
复制代码
1 2 3 4 5 |
|
我们知道volatile可以修饰数组的,只是意思和它表面上看起来的样子不同。举个栗子,volatile int array[10]是指array的地址是volatile的而不是数组元素的值是volatile的.
用volatile修饰的Node
get操作可以无锁是由于Node的元素val和指针next是用volatile修饰的,在多线程环境下线程A修改结点的val或者新增节点的时候是对线程B可见的。
[Java]
纯文本查看
复制代码
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
|