Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3590227
  • 博文数量: 365
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2522
  • 用 户 组: 普通用户
  • 注册时间: 2019-10-28 13:40
文章分类

全部博文(365)

文章存档

2023年(8)

2022年(130)

2021年(155)

2020年(50)

2019年(22)

我的朋友

分类: Java

2021-05-26 17:00:20

构造函数

先来看看几个重要的参数:

    /**

     * 默认初始容量,在没有在构造函数中另外指定时使用

     */

    static final int DEFAULT_INITIAL_CAPACITY = 16;

    /**

     * 默认加载因子,在没有在构造函数中另外指定时使用

     */

    static final float DEFAULT_LOAD_FACTOR = 0.75f;

    /**

     * 默认并发级别,在没有在构造函数中另外指定时使用。

     */

    static final int DEFAULT_CONCURRENCY_LEVEL = 16;

    /**

     * 最大容量,如果两个构造函数都使用参数隐式指定了更高的值,则使用该容量。

     * 必须是2的幂且小于等于 1 << 30,以确保条目可以使用int进行索引

     */

    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**

     * 每段表的最小容量。必须为2的幂,至少为2的幂,以免在延迟构造后立即调整下次使用时的大小。

     */

    static final int MIN_SEGMENT_TABLE_CAPACITY = 2;

    /**

     * 允许的最大段数;用于绑定构造函数参数。必须是小于1 << 242的幂。

     */

    static final int MAX_SEGMENTS = 1 << 16; // slightly conservative

    /**

     * 在锁定整个表之前,sizecontainsValue()方法的不同步重试次数。

     * 如果表进行连续修改,这将用于避免无限制的重试,这将导致无法获得准确的结果。

     */

    static final int RETRIES_BEFORE_LOCK = 2;

    /**

     * 用于编入段的掩码值。密钥的哈希码的高位用于选择段。

     */

    final int segmentMask;

    /**

     * 段内索引的移位值。

     */

    final int segmentShift;

    /**

     * 段,每个段都是一个专用的哈希表

     */

    final Segment[] segments;

上面的参数知道大概就行,在接下来的代码中就能理解这些参数的作用的,接下来看看构造方法:

/**

     * 使用指定的初始容量,负载因子和并发级别创建一个新的空映射。

     *

     * @param 初始容量。该实现执行内部大小调整以容纳许多元素。

     *

     * @param loadFactor  负载系数阈值,用于控制调整大小。

     * 当每个仓的平均元素数超过此阈值时,可以执行大小调整。

     *

     * @param concurrencyLevel 估计的并发更新线程数。该实现执行内部大小调整以尝试容纳这么多线程。

     *

     * @throws IllegalArgumentException 如果初始容量为负,或者负载因子或concurrencyLevel为非正数。

     */

    @SuppressWarnings("unchecked")

    public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) {

     //对非法输入进行处理

        if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)

            throw new IllegalArgumentException();

        // 若并发线程数大于最大段数,则等于最大段数    

        if (concurrencyLevel > MAX_SEGMENTS)

            concurrencyLevel = MAX_SEGMENTS;

        // 为保证能通过位与运算的散列算法来定位segments数组索引,要保证数组长度为2的幂,查找最适合参数的二乘幂

        int sshift = 0;

        int ssize = 1;

        while (ssize < concurrencyLevel) {

            ++sshift;

            ssize <<= 1;

        }

        this.segmentShift = 32 - sshift;

        this.segmentMask = ssize - 1;

        if (initialCapacity > MAXIMUM_CAPACITY)

            initialCapacity = MAXIMUM_CAPACITY;

        //初始化每个segment中的HashEntry长度

        int c = initialCapacity / ssize;

        //如果c大于1货币代码cap会取大于等于c2次方,所以cap要么等于1要么等于2的幂次方

        if (c * ssize < initialCapacity)

            ++c;

        int cap = MIN_SEGMENT_TABLE_CAPACITY;

        while (cap < c)

            cap <<= 1;

        // 创建segments数组,并初始化segments[0]

        Segment s0 = new Segment(loadFactor, (int)(cap * loadFactor),

                             (HashEntry[])new HashEntry[cap]);

        Segment[] ss = (Segment[])new Segment[ssize];

        UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]

        this.segments = ss;

    }

    public ConcurrentHashMap(int initialCapacity, float loadFactor) {

        this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);

    }

    public ConcurrentHashMap(int initialCapacity) {

        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);

    }

    public ConcurrentHashMap() {

        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);

    }

    public ConcurrentHashMap(Map m) {

        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);

        putAll(m);

    }

阅读(1925) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~