介绍一下Java容器的理解

1 介绍一下Java容器的理解?

1ArrayList

默认容量大小:private static final int DEFAULT_CAPACITY = 10;注意:如果没有向集合中添加任何元素时,容量是0,添加一个元素之后容量为10;当数组长度为10的时候每次扩容为原来的1.5倍;

ArrayList 在并发情况下是不安全的,CopyOnWriteArrayList:写入时复制,来解决这个问题,CopyOnWriteArrayList使用的是Lock锁,效率会更加高效,核心思想是,如果有多个调用者(Callers)同时要求相同的资源(如内存或者是磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的(transparently)。此做法主要的优点是如果调用者没有修改资源,就不会有副本(private copy)被创建,因此多个调用者只是读取操作时可以共享同一份资源。读的时候不需要加锁,如果读的时候有多个线程正在向CopyOnWriteArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的CopyOnWriteArrayList。CopyOnWriteArrayList 的设计思想1 读写分离,读和写分开2 最终一致性3 使用另外开辟空间的思路,来解决并发冲突缺点也是,另外开辟空间的方式:需要占用一定的内存空间;

ArrayList:必须开辟连续的空间,查询快,增删慢;
LinkedList:无需开辟一个连续的空间,增删慢,查询快;
在这里插入图片描述

2LinkedList

LinkedList:无需开辟一个连续的空间,增删慢,查询快;

3Vector

数组结构实现,查询快、增删慢;运行效率慢synchronized、线程安全。

4Set

无序、无下标、元素不可重复;
HashSet: 底层就是一个HashMap注:hashSet存储过程:
第一步:根据hashCode计算保存的位置,如果位置为空,则直接保存,否则执行第二步。
第二步:执行equals方法,如果方法返回true,则认为是重复,拒绝存储,否则形成链表。
TreeSet(红黑树):基于排序顺序实现不重复。实现了SortedSet接口,对集合元素自动排序。元素对象的类型必须实现Comparable接口,指定排序规则。通过CompareTo方法确定是否为重复元素。

Set和List同理可得: 多线程情况下,普通的Set集合是线程不安全的;
解决方案还是两种:1使用Collections工具类的synchronized包装的Set类 2使用CopyOnWriteArraySet

5Map

用于存储任意键值对(Key-Value)。键:无序、无下标、不允许重复(唯一)。值:无序、无下标、允许重复。 线程不安全,运行效率快;允许用null作为key或是value。存储结构:哈希表(数组+链表+红黑树);
默认初始化容量:static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16数组最大容量: 1 << 30;默认加载因子:0.75 f; //扩容
链表调整为红黑树链表长度阈值(JDK1.8):
static final int TREEIFY_THRESHOLD = 8;
红黑树调整为链表链表长度阈值(JDK1.8):
static final int UNTREEIFY_THRESHOLD = 6;
链表调整为红黑树数组最小阈值(JDK1.8):
static final int MIN_TREEIFY_CAPACITY = 64;

ConcurrentHashMap是Java中的一个线程安全且高效的HashMap实现。平时涉及高并发如果要用map结构,那第一时间想到的就是它。相对于hashmap来说,ConcurrentHashMap就是线程安全的map,其中利用了锁分段的思想提高了并发度。JDK 1.6版本关键要素:segment继承了ReentrantLock充当锁的角色,为每一个segment提供了线程安全的保障;segment维护了哈希散列表的若干个桶,每个桶由HashEntry构成的链表。JDK1.8后,ConcurrentHashMap抛弃了原有的Segment 分段锁,而采用了 CAS + synchronized 来保证并发安全性。

实现原理: HashMap采用链地址法。即底层是一个数组实现,数组的每一项(即一个Entry)又是一个链表。

HashMap的存储机制:首先根据key计算出该key对应的Entry在数组中的位置,然后判断该Entry是否在该位置对应的链表中,如果不在,则插入链表的头部,如果在,则更新该链表中对应Entry的value。

HashMap计算key所属数组的位置方法:首先计算key的hash值,然后根据hash函数hashcode & (length - 1)计算出所在数组的位置(因为HashMap的数组长度为2的整数幂,所以采用位运算的结果和hash % length相同,但是位运算的效率要远高于求余运算)

HashMap的扩容:每当初始化一个HashMap,默认的数组大小(table.size)为16(初始化阶段是没有16,是在添加元素的时候resize=16的),默认的增长因子(loadFactor)为0.75,;当元素个数超过数组大小的loadFactor 时,就会 对数组进行扩容。HashMap采用的扩容方法为:每次把数组大小扩大一倍,然后重新计算HashMap中每个元素在数组中的位置。也可以 自定义扩展容量的大小( HashMap(int initialCapacity))。

6Hashtable

JDK1.0版本,线程安全,运行效率慢不允许null作为key或是value。初始容量11,加载因子0.75。

7HashMap允许用null作为key或是value,为什么会这样?HashTable不允许key值为null,也不允许value为null;那么HashMap的null是如何存储区的呢?

  public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

8为什么ConcurrentHashMap那么好,还要使用HashMap?

ConcurrentHashMap是替代hashTable的一种方案,ConcurrentHashMap里使用了Segment分段锁+HashEntry,而HashTable用的是Syncronized锁全部,所有线程竞争一把锁。Segment分段锁继承ReentrantLock,**在并发数高的时候,ReentrantLock比Syncronized总体开销要小一些。**但是还是有开销的,HashMap就不会有这种开销!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值