Hashmap原理和concurrentHashMap

hashmap原理

1.put原理

主要思想就是插入的时候,首先根据key的hash值计算node数组的位置,并判断是否为空,如果为空就直接插入数据。如果不为空,就判断要插入的值是否与第一个数据相同,不相同就继续判断是不是红黑树,是就遍历红黑树,否则继续遍历链表遇到相同的就终止。采用的是尾插,插入之后判断是否达到阈值,容量乘以负载因子0.75,达到之后就扩容。

主体就是数组+链表+红黑树

public V put(K key, V value) {
        return this.putVal(hash(key), key, value, false, true);
    }

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
        HashMap.Node[] tab;
        int n;
        if ((tab = this.table) == null || (n = tab.length) == 0) {
            n = (tab = this.resize()).length;
        }

        Object p;
        int i;
        if ((p = tab[i = n - 1 & hash]) == null) {
            tab[i] = this.newNode(hash, key, value, (HashMap.Node)null);
        } else {
            Object e;
            Object k;
            if (((HashMap.Node)p).hash == hash && ((k = ((HashMap.Node)p).key) == key || key != null && key.equals(k))) {
                e = p;
            } else if (p instanceof HashMap.TreeNode) {
                e = ((HashMap.TreeNode)p).putTreeVal(this, tab, hash, key, value);
            } else {
                int binCount = 0;

                while(true) {
                    if ((e = ((HashMap.Node)p).next) == null) {
                        ((HashMap.Node)p).next = this.newNode(hash, key, value, (HashMap.Node)null);
                        if (binCount >= 7) {
                            this.treeifyBin(tab, hash);
                        }
                        break;
                    }

                    if (((HashMap.Node)e).hash == hash && ((k = ((HashMap.Node)e).key) == key || key != null && key.equals(k))) {
                        break;
                    }

                    p = e;
                    ++binCount;
                }
            }

            if (e != null) {
                V oldValue = ((HashMap.Node)e).value;
                if (!onlyIfAbsent || oldValue == null) {
                    ((HashMap.Node)e).value = value;
                }

                this.afterNodeAccess((HashMap.Node)e);
                return oldValue;
            }
        }

        ++this.modCount;
        if (++this.size > this.threshold) {
            this.resize();
        }

        this.afterNodeInsertion(evict);
        return null;
    }

2.get原理

主要思想就是插入的时候,首先根据key的hash值计算node数组的位置。首先比较位置上面第一个值是否相等,不相等就判断结构是不是红黑树,是就去查询,否则就遍历链表。

public V get(Object key) {
        HashMap.Node e;
        return (e = this.getNode(hash(key), key)) == null ? null : e.value;
    }

    final HashMap.Node<K, V> getNode(int hash, Object key) {
        HashMap.Node[] tab;
        HashMap.Node first;
        int n;
        if ((tab = this.table) != null && (n = tab.length) > 0 && (first = tab[n - 1 & hash]) != null) {
            Object k;
            if (first.hash == hash && ((k = first.key) == key || key != null && key.equals(k))) {
                return first;
            }

            HashMap.Node e;
            if ((e = first.next) != null) {
                if (first instanceof HashMap.TreeNode) {
                    return ((HashMap.TreeNode)first).getTreeNode(hash, key);
                }

                do {
                    if (e.hash == hash && ((k = e.key) == key || key != null && key.equals(k))) {
                        return e;
                    }
                } while((e = e.next) != null);
            }
        }

        return null;
    }

concurrenthashmap原理

因为多了casTabAt(tab, i, (ConcurrentHashMap.Node)null, new ConcurrentHashMap.Node(hash, key, value)) 和syncroniczed,所以线程安全

1.put原理

final V putVal(K key, V value, boolean onlyIfAbsent) {
        if (key != null && value != null) {
            int hash = spread(key.hashCode());
            int binCount = 0;
            ConcurrentHashMap.Node[] tab = this.table;

            while(true) {
                int n;
                while(tab == null || (n = tab.length) == 0) {
                    tab = this.initTable();
                }

                ConcurrentHashMap.Node f;
                int i;
                if ((f = tabAt(tab, i = n - 1 & hash)) == null) {
                    if (casTabAt(tab, i, (ConcurrentHashMap.Node)null, new ConcurrentHashMap.Node(hash, key, value))) {
                        break;
                    }
                } else {
                    int fh;
                    if ((fh = f.hash) == -1) {
                        tab = this.helpTransfer(tab, f);
                    } else {
                        Object fk;
                        Object fv;
                        if (onlyIfAbsent && fh == hash && ((fk = f.key) == key || fk != null && key.equals(fk)) && (fv = f.val) != null) {
                            return fv;
                        }

                        V oldVal = null;
                        synchronized(f) {
                            if (tabAt(tab, i) == f) {
                                if (fh < 0) {
                                    if (f instanceof ConcurrentHashMap.TreeBin) {
                                        binCount = 2;
                                        ConcurrentHashMap.TreeNode p;
                                        if ((p = ((ConcurrentHashMap.TreeBin)f).putTreeVal(hash, key, value)) != null) {
                                            oldVal = p.val;
                                            if (!onlyIfAbsent) {
                                                p.val = value;
                                            }
                                        }
                                    } else if (f instanceof ConcurrentHashMap.ReservationNode) {
                                        throw new IllegalStateException("Recursive update");
                                    }
                                } else {
                                    label124: {
                                        binCount = 1;

                                        ConcurrentHashMap.Node e;
                                        Object ek;
                                        for(e = f; e.hash != hash || (ek = e.key) != key && (ek == null || !key.equals(ek)); ++binCount) {
                                            ConcurrentHashMap.Node<K, V> pred = e;
                                            if ((e = e.next) == null) {
                                                pred.next = new ConcurrentHashMap.Node(hash, key, value);
                                                break label124;
                                            }
                                        }

                                        oldVal = e.val;
                                        if (!onlyIfAbsent) {
                                            e.val = value;
                                        }
                                    }
                                }
                            }
                        }

                        if (binCount != 0) {
                            if (binCount >= 8) {
                                this.treeifyBin(tab, i);
                            }

                            if (oldVal != null) {
                                return oldVal;
                            }
                            break;
                        }
                    }
                }
            }

            this.addCount(1L, binCount);
            return null;
        } else {
            throw new NullPointerException();
        }
    }

2.get原理

public V get(Object key) {
        int h = spread(key.hashCode());
        ConcurrentHashMap.Node[] tab;
        ConcurrentHashMap.Node e;
        int n;
        if ((tab = this.table) != null && (n = tab.length) > 0 && (e = tabAt(tab, n - 1 & h)) != null) {
            int eh;
            Object ek;
            if ((eh = e.hash) == h) {
                if ((ek = e.key) == key || ek != null && key.equals(ek)) {
                    return e.val;
                }
            } else if (eh < 0) {
                ConcurrentHashMap.Node p;
                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;
    }

总结

hashmap的原理 如上源码。
hash冲突的解决方式1.开放寻址法 2.链地址法 hashmap采用后一种

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值