java并发系列五(并发集合,原子类)

本文深入探讨Java并发编程中的并发集合,重点关注ConcurrentHashMap在Java 7和8中的实现差异。Java 7采用锁分段策略,而Java 8则利用数组+链表+红黑树实现。文章详细解析了ConcurrentHashMap的put操作流程,包括初始化、扩容以及链表转红黑树的过程。此外,还介绍了原子类AtomicInteger的工作原理,强调了CAS操作在保证并发安全中的作用。
摘要由CSDN通过智能技术生成

1,并发集合

一,concurrentHashMap!!!(超重点)
这里对concurrentHashMap的讲解分为jdk7和jdk8。
两个版本有了很大的变化
java7中着重讲解分段锁,java8中concurrentHashMap是基于数组加链表加红黑树实现的
1,java7中concurrentHashMap的实现
锁的粒度的减少有2钟方式,锁分解和锁分段。java7中concurrentHashMap就是基于锁分段实现的。它的实现使用了一个包含16个锁的数组,即Segment数组。默认每个锁具有散列桶的1/16.其中第N个桶由,其中,第N个散列桶由第(N mod 16)来保护。Segment数组长度即为并发数。

在这里插入图片描述
每个Segment元素存储的是HashEntry数组+链表。
put操作
会进行两次hash去定位Segment下的HashEntry的位置。然后接下来,我们注意一哈。。。首先我们看一下这个,如下

static class Segment<K,V> extends ReentrantLock implements Serializable {

它继承了锁的特性,当定位到位置时,会通过tryLock()尝试获取锁,如果获得就插入。否则自旋获取锁,超过指定次数就挂起,等待唤醒。
2,java8中concurrentHashMap的实现
上面讲过,java8中,concurrentHashMap是由红黑树+链表+数组实现的。
首先,来讲一下concurrentHashMap中的几个重要内部类
Node,TreeNode,TreeBin

Node
Node是存储结构的基本单元,实现了Map.Entry接口。
源码如下。

static class Node<K,V> implements Map.Entry<K,V> {
    //链表的数据结构
    final int hash;
    final K key;
    //val和next都会在扩容时发生变化,所以加上volatile来保持可见性和禁止重排序
    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;
    }
    public final K getKey()       { return key; }
    public final V getValue()     { return val; }
    public final int hashCode()   { return key.hashCode() ^ val.hashCode(); }
    public final String toString(){ return key + "=" + val; }
    //不允许更新value 
    public final V setValue(V value) {
        throw new UnsupportedOperationException();
    }
    public final boolean equals(Object o) {
        Object k, v, u; Map.Entry<?,?> e;
        return ((o instanceof Map.Entry) &&
                (k = (e = (Map.Entry<?,?>)o).getKey()) != null &&
                (v = e.getValue()) != null &&
                (k == key || k.equals(key)) &&
                (v == (u = val) || v.equals(u)));
    }
    //用于map中的get()方法,子类重写
    Node<K,V> find(int h, Object k) {
        Node<K,V> e = this;
        if (k != null) {
            do {
                K ek;
                if (e.hash == h &&
                    ((ek = e.key) == k || (ek != null && k.equals(ek))))
                    return e;
            } while ((e = e.next) != null);
        }
        return null;
    }
}

很容易看出Node就是一个存储的链表,但只允许进行查找。其中有点需要注意:它对value和next属性设置了volatile同步锁。

TreeNode
TreeNode继承于Node,不同的是它是二叉树的存储结构,并非链表。
用于在红黑树中存储数据。
conCurrentHashMap中链表节点数大于8时会转换成红黑树结构。此时,TreeNode就会代替Node来存储数据,源码如下

static final class TreeNode<K,V> extends Node<K,V> {
    //树形结构的属性定义
    TreeNode<K,V> parent;  // red-black tree links
    TreeNode<K,V> left;
    TreeNode<K,V> right;
    TreeNode<K,V> prev;    // needed to unlink next upon deletion
    boolean 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);
    }
    //根据key查找 从根节点开始找出相应的TreeNode,
    final TreeNode<K,V> findTreeNode(int h, Object k, Class<?> kc) {
        if (k != null) {
            TreeNode<K,V> p = this;
            do  {
                int ph, dir; K pk; TreeNode<K,V> q;
                TreeNode<K,V> pl = p.left, pr = p.right;
                if ((ph = p.hash) > h)
                    p = pl;
                else if (ph < h)
                    p = pr;
                else if ((pk = p.key) == k || (pk != null && k.equals(pk)))
                    return p;
                else if (pl == null)
                    p = pr;
                else if (pr == null)
                    p = pl;
                else if ((kc != null ||
                          (kc = comparableClassFor(k)) != null) &&
                         (dir = compareComparables(kc, k, pk)) != 0)
                    p = (dir < 0) ? pl : pr;
                else if ((q = pr.findTreeNode(h, k, kc)) != null)
                    return q;
                else
                    p = pl;
            } while (p != null);
        }
        return null;
    }
}

TreeBin
上面说过,TreeBin用来包装TreeNode。它提供了转换红黑树的一些条件和锁的控制。它还带了读写锁。部分源码如下

static final class TreeBin<K,V> extends Node<K,V> {
    //指向TreeNode列表和根节点
    TreeNode<K,V> root;
    volatile TreeNod
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值