今天是2021-2-24.
一。arraylist
1.arraylist最大容量:Integer.MAX_VALUE
二,hashmap
1.构造hashmap时,我们指定的初始容量A会被扩大到比它大的最近的那个2的n次幂的值B,以方便在扩容的时候,计算数据在 newTable 中的位置。
2.扩容阈值会由B0.75得出
3.如果我们想存数据量大的数据,比如说1000,最好是看比1000大的那个2的n次幂的值0.75是否比它小–1024*0.75=768<1000,这样想存1000条还要触发一次扩容
4.方便起见,我们想指定初始容量时,传入预期值/0.75,通过负载因子放大,就可以保证存放下预期数据量的数据
为什么hashmap的容量总是满足2的n次幂
假设底层数组长度n
- 计算索引的公式为:(n-1)&hash
- 如果满足2的n次幂,添加元素时就能保证数组中每个索引都可能被使用,就可以大大减少hash冲突的概率。如果不满足,那么数组中有些索引可能永远都不会被使用,浪费了空间。
- 在查找元素时,也是通过(n-1)&hash去得出索引,如果索引上存放的是链表,意味着之前添加元素的时候是发生了hash冲突的,那么就要匹配链表直到找到匹配key,查询的效率就会降低
- jdk1.7在扩容时,原数组的元素都要进行rehash(),重新计算每个元素的hash值,然后计算在新数组中的索引位置,如果不满足,那么就会降低使用率,增加hash冲突。jdk1.8在扩容时,不重新计算hash值,直接通过(n-1)&hash得到索引,元素要么还在原位置,要么在原位置+数组原长度处。
头插法
获取当前索引上的元素e,也就是原链表的表头,然后以e作为新entry的next属性的值,也就是说新元素指向了原来的表头,那么这个新元素自然成为了新链表的表头
头插法的死循环
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
Entry<K,V> next = e.next;
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
//通过key值的hash值和新数组的大小算出在当前数组中的存放位置
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}
假设有两个线程t1和t2,链表有元素a,b,a->b->null
从e=a开始
- t1执行next=a.next=b后挂起
- t2开始工作,向新链表插入a元素,此时e=a.next=b,新链表是a->null
- t2新一轮循环,此时e=b,b.next=newTable[i]=a,b->a,将b插入t2新链表,此时新链表就变成了b->a->null
- t1重新开始工作e=a,next=b,a.next=newTable[i]=null,e=next=b,t1新链表是a->null
- t1新一轮循环,e=b,next=b.next=a,b.next=newTable[i]=a,b->a,将b插入新链表,则新链表为b->a->null,e=next=a
- t1继续循环,此时e=a,next=a.next=null,a.next=newTable[i]=b,a->b,将a插入新链表,则新链表为a->b->a,e=next=null结束循环
- 结束循环后,的新链表已经是a->b->a的环链表了,如果尝试获取一个key为c的键值对,那么就会因为获取不到而在a、b之间不断循环判断下一个元素是否匹配,从而死循环
三。cookie禁用了怎么实现登录效果
前端使用LocalStorage替代,转
限制cookie滥用,可以用localStorage替代大部分cookie功能
四。Thread类
1.实现了Runnable接口
2.yield()方法:与sleep()类似,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。
3.join()方法:
join()
join(long millis) //参数为毫秒
join(long millis,int nanoseconds) //第一参数为毫秒,第二个参数为纳秒
假如在main线程中,调用thread.join方法,则main方法会等待thread线程执行完毕或者等待一定的时间。如果调用的是无参join方法,则等待thread执行完毕,如果调用的是指定了时间参数的join方法,则等待一定的时间
3.1 实际上调用join方法是调用了Object的wait方法
3.2interrupt()是给线程设置中断标志;interrupted()是检测中断并清除中断状态;isInterrupted()只检测中断。还有重要的一点就是interrupted()作用于当前线程,interrupt()和isInterrupted()作用于此线程,即代码中调用此方法的实例所代表的线程。