没有特别说明线程安全,代表线程不安全
相等的对象必须具有相等的hashCode
java.util.Collection
接口, Map接口没有继承java.util.Collection接口容器容量大小*负载因子
,就要resizekey.equals(k)
去查找对应的entry:若为树则在树中通过key.equals(k)查找O(logn)
; 若为链表则在链表中通过key.equals(k)查找O(n)
容器容量大小*负载因子
就要扩容原索引+2的n次方
扩容的时候需要重新计算Hash吗? 1.8之前需要,1.8中不需要. 在1.8中元素的位置要么是在原位置,要么是在原位置再移动2次幂的位置
HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap元素插入的顺序,也就是无序,而LinkedHashMap是有序的。
accessOrder=true
来达到按访问顺序排序的效果,也就是访问一个元素之后,会将它放到尾部accessOrder=true
来达到按访问顺序遍历LinkedHashMap的效果。什么叫访问顺序?即通过get
方法访问的元素,会放到链表尾部,也就是按照了访问时间进行排序,基于这个特性和LinkedHashMap虽然可以根据插入顺序和访问顺序排序,但是无法自定义排序规则,而TreeMap可以
key#compareTo
方法进行比较,此种情况key必须实现Comparable接口;或者根据创建映射时提供的Comparator
进行排序synchronized
实现,效率低CAS+synchronized
实现(锁粒度更细), 相对HashTable来说,性能好很多java.util.Collection
接口, Map接口没有继承java.util.Collection接口System.arraycopy
,效率很低,所以最好在初始化的时候指定大小增删操作
都相对低效, 而改查操作
比较高效arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
src:源数组;
srcPos:源数组要复制的起始位置;
dest:目的数组;
destPos:目的数组放置的起始位置;
length:复制的长度;
src 和 dest 必须是同类型或者可以进行转换类型的数组
ReentrantLock
获取锁,然后基于原数组复制出一个新的数组,在新数组的基础上修改java.util.Collection
接口, Map接口没有继承java.util.Collection接口private static final Object PRESENT = new Object()
map.keySet().iterator()
. 也就是说HashSet依赖于HashMap实现,仅仅是利用了HashMap的key,value只是一个常量对象,没有什么意义
LinkedHashSet
底层使用LinkedHashMap
来保存所有元素,它继承自HashSet
,其所有的方法操作上又与HashSet
相同CopyOnWriteArrayList
引用,也就是说它的实现完全基于CopyOnWriteArrayList
ConcurrentModificationException
Iterator
时通过expectedModCount
记录了当前的修改次数,在迭代时判断expectedModCount
是否与modCount
相等,不相等则抛出ConcurrentModificationException
ThreadLocal
中有一个内部类:ThreadLocalMap
. 数据会被封装成Entry
然后存到ThreadLocalMap
中Thread
中有一个ThreadLocalMap
类型的属性:threadLocals
threadLocals
属性值为null,则创建一个ThreadLocalMap
对象并赋值给当前线程的threadLocals
属性,然后以ThreadLocal
本身为key,将值存到ThreadLocalMap
对象中threadLocals
属性值(即ThreadLocalMap
对象),然后以ThreadLocal
本身为key从ThreadLocalMap
对象中获取值public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
为什么ThreadLocalMap中的元素(Entry)要继承弱引用类WeakReference?
ThreadLocalMap
中的key就是ThreadLocal
对象本身,这时就会和Entry对象存在强引用关联而无法被GC回收,造成内存泄漏. 除非线程结束后,线程被回收了,线程中的ThreadLocalMap也跟着回收ThreadLocal什么情况下会造成内存泄漏问题?
threadLocals
属性还指向了那个ThreadLocalMap对象,即存在一条强引用. 如果该线程没有被回收(例如线程池),那就存在内存泄漏问题.