日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java并发编程之并发容器ConcurrentHashMap(JDK1.8)解析

發(fā)布時(shí)間:2025/3/11 java 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java并发编程之并发容器ConcurrentHashMap(JDK1.8)解析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

這個(gè)版本ConcurrentHashMap難度提升了很多,就簡單的談一下常用的方法就好了,可能有些講的不太清楚,麻煩發(fā)現(xiàn)的大佬指正一下

主要數(shù)據(jù)結(jié)構(gòu)

1.8將Segment取消了,保留了table數(shù)組的形式,但是不在以HashEntry純鏈表的形式儲(chǔ)存數(shù)據(jù)了,采用了鏈表+紅黑樹的形式儲(chǔ)存數(shù)據(jù);在使用get()方法時(shí),使用純鏈表的時(shí)間復(fù)雜度時(shí)O(n),而在使用紅黑樹的數(shù)據(jù)結(jié)構(gòu)時(shí),時(shí)間復(fù)雜度為O(logn),在查詢的速度上有很大的提升;但是在創(chuàng)建的時(shí)候并非直接使用紅黑樹儲(chǔ)存數(shù)據(jù),而是依舊采用鏈表存儲(chǔ),但是但鏈表的長度超過8的時(shí)候就會(huì)轉(zhuǎn)換成紅黑樹數(shù)據(jù)結(jié)構(gòu)。

Node

依舊還是跟HashEntry的數(shù)據(jù)結(jié)構(gòu)一致,采用鏈表的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)

static class Node<K,V> implements Map.Entry<K,V> {final int hash;final K key;volatile V val;volatile Node<K,V> next;Node(int hash, K key, V val, Node<K,V> next) {this.hash = hash;this.key = key;this.val = val;this.next = next;}//.....}

TreeNode

紅黑樹的數(shù)據(jù)結(jié)構(gòu)原型,繼承了Node

/*** Nodes for use in TreeBins*/static final class TreeNode<K,V> extends Node<K,V> {TreeNode<K,V> parent; // red-black tree linksTreeNode<K,V> left;TreeNode<K,V> right;TreeNode<K,V> prev; // needed to unlink next upon deletionboolean red;TreeNode(int hash, K key, V val, Node<K,V> next,TreeNode<K,V> parent) {super(hash, key, val, next);this.parent = parent;}Node<K,V> find(int h, Object k) {return findTreeNode(h, k, null);}//......}

TreeBin

table數(shù)組中儲(chǔ)存的就是TreeBin對(duì)象,存儲(chǔ)了TreeNode<K,V>的根節(jié)點(diǎn)

static final class TreeBin<K,V> extends Node<K,V> {TreeNode<K,V> root;volatile TreeNode<K,V> first;volatile Thread waiter;volatile int lockState;// values for lockStatestatic final int WRITER = 1; // set while holding write lockstatic final int WAITER = 2; // set when waiting for write lockstatic final int READER = 4; // increment value for setting read lock//...}

構(gòu)造方法

在構(gòu)造方法中,并沒有做什么操作,僅僅是設(shè)置了一個(gè)屬性值sizeCtl(也是容器的控制器)

sizeCtl:

負(fù)數(shù):表示進(jìn)行初始化或者擴(kuò)容,-1表示正在初始化,-N,表示有N-1個(gè)線程正在進(jìn)行擴(kuò)容。

正數(shù):0 表示還沒有被初始化,>0的數(shù),初始化或者是下一次進(jìn)行擴(kuò)容的閾值。

而實(shí)際的初始化是在put()方法中加載table數(shù)組

/*** The array of bins. Lazily initialized upon first insertion.* Size is always a power of two. Accessed directly by iterators.*/transient volatile Node<K,V>[] table;/*** Table initialization and resizing control. When negative, the* table is being initialized or resized: -1 for initialization,* else -(1 + the number of active resizing threads). Otherwise,* when table is null, holds the initial table size to use upon* creation, or 0 for default. After initialization, holds the* next element count value upon which to resize the table.*/private transient volatile int sizeCtl; /*** Creates a new, empty map with the default initial table size (16).*/public ConcurrentHashMap() {}/*** Creates a new, empty map with an initial table size* accommodating the specified number of elements without the need* to dynamically resize.** @param initialCapacity The implementation performs internal* sizing to accommodate this many elements.* @throws IllegalArgumentException if the initial capacity of* elements is negative*/public ConcurrentHashMap(int initialCapacity) {if (initialCapacity < 0)throw new IllegalArgumentException();int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?MAXIMUM_CAPACITY :tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));this.sizeCtl = cap;}

put()方法

具體調(diào)用了putVal(),依舊還是和putIfAbsent()調(diào)用的是同一個(gè)方法,ConcurrentHashMap容器初始化實(shí)在put()方法中加載的即initTable();方法;

這個(gè)版本計(jì)算hash值的方法為spread(object.hashCode()),在創(chuàng)建完table數(shù)組之后,接下來就是創(chuàng)建數(shù)組中的Node節(jié)點(diǎn)了,會(huì)判斷當(dāng)前是鏈表還是紅黑樹,然后將數(shù)據(jù)插入到對(duì)應(yīng)的鏈表或樹中,鏈表插入一個(gè)數(shù)據(jù)binCount就會(huì)自增,然后當(dāng)這個(gè)值大于一個(gè)閾值時(shí)就會(huì)進(jìn)入到鏈表轉(zhuǎn)紅黑樹方法treeifyBin

/*** Initializes table, using the size recorded in sizeCtl.*/ //采用了CAS設(shè)置了sizeCtl的值private final Node<K,V>[] initTable() {Node<K,V>[] tab; int sc;while ((tab = table) == null || tab.length == 0) {if ((sc = sizeCtl) < 0)Thread.yield(); // lost initialization race; just spinelse if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {try {if ((tab = table) == null || tab.length == 0) {int n = (sc > 0) ? sc : DEFAULT_CAPACITY;@SuppressWarnings("unchecked")//創(chuàng)建table數(shù)組Node<K,V>[] nt = (Node<K,V>[])new Node<?,?>[n];table = tab = nt;//sc = 0.75n,即擴(kuò)容因子還是0.75sc = n - (n >>> 2);}} finally {sizeCtl = sc;}break;}}return tab;}//計(jì)算key的hash值,與1.7相比,更加均勻static final int spread(int h) {return (h ^ (h >>> 16)) & HASH_BITS;} /** Implementation for put and putIfAbsent */final V putVal(K key, V value, boolean onlyIfAbsent) {if (key == null || value == null) throw new NullPointerException();int hash = spread(key.hashCode());int binCount = 0;for (Node<K,V>[] tab = table;;) {Node<K,V> f; int n, i, fh;if (tab == null || (n = tab.length) == 0)tab = initTable();else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null)))break; // no lock when adding to empty bin}else if ((fh = f.hash) == MOVED)tab = helpTransfer(tab, f);else {V oldVal = null;synchronized (f) {if (tabAt(tab, i) == f) {if (fh >= 0) {//進(jìn)入到鏈表binCount = 1;for (Node<K,V> e = f;; ++binCount) {K ek;if (e.hash == hash &&((ek = e.key) == key ||(ek != null && key.equals(ek)))) {oldVal = e.val;if (!onlyIfAbsent)e.val = value;break;}Node<K,V> pred = e;if ((e = e.next) == null) {pred.next = new Node<K,V>(hash, key,value, null);break;}}}else if (f instanceof TreeBin) {//進(jìn)入到紅黑樹Node<K,V> p;binCount = 2;if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,value)) != null) {oldVal = p.val;if (!onlyIfAbsent)p.val = value;}}}}if (binCount != 0) {if (binCount >= TREEIFY_THRESHOLD)treeifyBin(tab, i);if (oldVal != null)return oldVal;break;}}}addCount(1L, binCount);return null;}/*** Replaces all linked nodes in bin at given index unless table is* too small, in which case resizes instead.*///將Node<>[]中的鏈表換成紅黑樹的TreeBinprivate final void treeifyBin(Node<K,V>[] tab, int index) {Node<K,V> b; int n, sc;if (tab != null) {if ((n = tab.length) < MIN_TREEIFY_CAPACITY)tryPresize(n << 1);else if ((b = tabAt(tab, index)) != null && b.hash >= 0) {synchronized (b) {if (tabAt(tab, index) == b) {TreeNode<K,V> hd = null, tl = null;for (Node<K,V> e = b; e != null; e = e.next) {TreeNode<K,V> p =new TreeNode<K,V>(e.hash, e.key, e.val,null, null);if ((p.prev = tl) == null)hd = p;elsetl.next = p;tl = p;}setTabAt(tab, index, new TreeBin<K,V>(hd));}}}}}

在put()的時(shí)候有個(gè)擴(kuò)容的方法helpTransfer(tab, f);?

/*** Helps transfer if a resize is in progress.*/final Node<K,V>[] helpTransfer(Node<K,V>[] tab, Node<K,V> f) {Node<K,V>[] nextTab; int sc;if (tab != null && (f instanceof ForwardingNode) &&(nextTab = ((ForwardingNode<K,V>)f).nextTable) != null) {int rs = resizeStamp(tab.length);while (nextTab == nextTable && table == tab &&(sc = sizeCtl) < 0) {if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||sc == rs + MAX_RESIZERS || transferIndex <= 0)break;if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1)) {//擴(kuò)容table數(shù)組transfer(tab, nextTab);break;}}return nextTab;}return table;}

get()

首先獲取到key值的hash值,然后去定位是數(shù)組中的哪個(gè)Node節(jié)點(diǎn),然后去遍歷鏈表或者紅黑樹查找;

public V get(Object key) {Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek;int h = spread(key.hashCode());//獲取key的對(duì)應(yīng)的hash值if ((tab = table) != null && (n = tab.length) > 0 &&(e = tabAt(tab, (n - 1) & h)) != null) {if ((eh = e.hash) == h) {//判斷是否為當(dāng)前數(shù)組元素if ((ek = e.key) == key || (ek != null && key.equals(ek)))return e.val;}//從鏈表中獲取數(shù)據(jù)else if (eh < 0)return (p = e.find(h, key)) != null ? p.val : null;//從紅黑樹中獲取while ((e = e.next) != null) {if (e.hash == h &&((ek = e.key) == key || (ek != null && key.equals(ek))))return e.val;}}return null;}

結(jié)語:這玩意難度有點(diǎn)高啊,想要真正的看懂還需努力!

總結(jié)

以上是生活随笔為你收集整理的Java并发编程之并发容器ConcurrentHashMap(JDK1.8)解析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。