Java集合类
List
ArrayList
ArrayList默认容量是10,如果初始化时一开始指定了容量,或者通过集合作为元素,则容量为指定的大小或参数集合的大小。每次扩容为原来的1.5倍,如果新增后超过这个容量,则容量为新增后所需的最小容量。如果增加0.5倍后的新容量超过限制的容量,则用所需的最小容量与限制的容量进行判断,超过则指定为Integer的最大值,否则指定为限制容量大小。然后通过数组的复制将原数据复制到一个更大(新的容量大小)的数组。
modCount记录的是关于元素的数目被修改的次数。modCount在ArrayList的普通操作里可能并没有看出多大用处,但是在涉及到fail-fast就主要是依靠它了。
不允许读的时候被修改。
CopyOnWriteArrayList 线程安全
LinkedList
LinkedList的本质是双向链表。
(01) LinkedList继承于AbstractSequentialList,并且实现了Dequeue接口。
(02) LinkedList包含两个重要的成员:header 和 size。
header是双向链表的表头,它是双向链表节点所对应的类Entry的实例。Entry中包含成员变量: previous, next, element。其中,previous是该节点的上一个节点,next是该节点的下一个节点,element是该节点所包含的值。
size是双向链表中节点的个数。
LinkedList可以作为FIFO(先进先出)的队列,作为FIFO的队列时,下表的方法等价:
队列方法 等效方法 add(e) addLast(e) offer(e) offerLast(e) remove() removeFirst() poll() pollFirst() element() getFirst() peek() peekFirst()
LinkedList可以作为LIFO(后进先出)的栈,作为LIFO的栈时,下表的方法等价:
栈方法 等效方法 push(e) addFirst(e) pop() removeFirst() peek() peekFirst()
Set
(01) Set 是继承于Collection的接口。它是一个不允许有重复元素的集合。
(02) AbstractSet 是一个抽象类,它继承于AbstractCollection,AbstractCollection实现了Set中的绝大部分函数,为Set的实现类提供了便利。
(03) HastSet 和 TreeSet 是Set的两个实现类。
HashSet依赖于HashMap,它实际上是通过HashMap实现的。HashSet中的元素是无序的。
TreeSet依赖于TreeMap,它实际上是通过TreeMap实现的。TreeSet中的元素是有序的。
Queue
可以把LinkedList当Queue用,poll=get,offer=add
concurrent包内BlockQueue
final ReentrantLock lock; private final Condition notEmpty; private final Condition notFull; notEmpty = lock.newCondition(); notFull = lock.newCondition(); PUT public void put(E e) throws InterruptedException { checkNotNull(e); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == items.length) // 判断元素是否已满 notFull.await(); enqueue(e); } finally { lock.unlock(); private void enqueue(E x) { final Object[] items = this.items; items[putIndex] = x; if (++putIndex == items.length) // 放入后存元素的索引等于数组长度(表示已满) putIndex = 0; count++; notEmpty.signal(); }
poll函数用于获取元素,其与offer函数相对应,不会抛出异常,当元素个数为0是,返回null,否则,调用dequeue函数,并唤醒等待notFull条件的线程。并返回。
public E take() throws InterruptedException { // 可重入锁 final ReentrantLock lock = this.lock; // 如果当前线程未被中断,则获取锁,中断会抛出异常 lock.lockInterruptibly(); try { while (count == 0) // 元素数量为0,即Object数组为空 // 则等待notEmpty条件 notEmpty.await(); // 出队列 return dequeue(); } finally { // 释放锁 lock.unlock(); } } private E dequeue() { // assert lock.getHoldCount() == 1; // assert items[takeIndex] != null; final Object[] items = this.items; @SuppressWarnings("unchecked") // 取元素 E x = (E) items[takeIndex]; // 该索引的值赋值为null items[takeIndex] = null; // 取值索引等于数组长度 if (++takeIndex == items.length) // 重新赋值取值索引 takeIndex = 0; // 元素个数减1 count--; if (itrs != null) itrs.elementDequeued(); // 唤醒在notFull条件上等待的线程 notFull.signal(); return x; }
ArrayBlockingQueue实现的队列中的锁是没有分离的,即添加操作和移除操作采用的同一个ReenterLock锁,而LinkedBlockingQueue实现的队列中的锁是分离的,其添加采用的是putLock,移除采用的则是takeLock,这样能大大提高队列的吞吐量,也意味着在高并发的情况下生产者和消费者可以并行地操作队列中的数据,以此来提高整个队列的并发性能。
Map
TreeMap
TreeMap 是一个有序的key-value集合,它是通过红黑树实现的。
TreeMap 继承于AbstractMap,所以它是一个Map,即一个key-value集合。
TreeMap 实现了NavigableMap接口,意味着它支持一系列的导航方法。比如返回有序的key集合。
TreeMap 实现了Cloneable接口,意味着它能被克隆。
TreeMap 实现了java.io.Serializable接口,意味着它支持序列化。
TreeMap基于红黑树(Red-Black tree)实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
TreeMap的基本操作 containsKey、get、put 和 remove 的时间复杂度是 log(n) 。
另外,TreeMap是非同步的。 它的iterator 方法返回的迭代器是fail-fastl的。