地址:https://www.bilibili.com/video/bv1x741117jq/?spm_id_from=333.788.b_636f6d6d656e74.7
JDK7的HashMap。
---
链表:JDk7是插入到链表的头部是比较快的,插到尾部是比较慢的因为需要遍历的。
--
get的方法是如何实现的?首先获得key的hashCode重写的话就用重写的,否则用系统的,这个hash是比较麻烦的,之后取余(&(n-1)),然后找到在数组的下标。
--
头插法,先插入到头节点,然后向后移动一位,当前的头放在数组里面。
实现:数组存的是引用,实际找的话就是找到引用对应的对象然后让这个对象的next指针,指向下一个节点。
---
加载因子。
看下put方法。
map的底层实现:https://www.cnblogs.com/dijia478/p/8006713.html
---
hashmap的属性:
看下这个方法:
10就是16。
左移一位就是*2。
hash方法:
hash算出序号的要求:
1.不越界
2.尽量均匀
为什么是2的n次方,可以保证的是-1之后1多。为什么-1,因为最大的下标是-1。
有什么高低位做异或运算,为了让高位和低位一起影响。
为什么异或会深远的影响呢?
举例:
1111与0101
与:0101不变高位不起作用
或:1111完全被高位控制
异或:1010扰动成功
---
key==null的问题。
addEntry:
---281---
扩容:p2
扩容:
扩容会翻倍的。
如何转移的呢?
扩容后还是原来的index或者index+旧数组的长度,前提是没有重新rehash。
---
两个线程同时扩容的情况呢?
两个线程同时进入这个方法:
内部生成这个数组。
老数组是一个每个线程都会建新的数组。
扩容就是创建新的数组然后全部转移。
假设第2个线程执行到了箭头就卡住了,第一个线程顺利执行完毕。
源头就是头插法的原因的。
为什么是2的n次幂:https://blog.csdn.net/apeopl/article/details/88935422
---
看下rehash:默认为false
什么是hash种子,什么时候为true。
---
这个会报错的。
看下源码:
这个是用迭代器的迭代方法。
看下remove得方法:
modCount是修改得次数。
正确得写法:
为什么:
modCount是快速失败的,记录的是操作的次数的。
两个线程一个遍历,一个删除就会快速失败。
------------------------------------------------
ConcurrentHashMap。
---
JDK7的concurrentHashMap:https://blog.csdn.net/Adrian_Dai/article/details/81429896
一个segment里面最小的是2个Entry数组。
扩容是单个segment扩容。
存segment数组的长度是固定的=线程安全数。
初始化时候有一个segment[0],存初始化信息,这样再new segment就不用再计算了。
---
unsafe方法:
var0是表示当前是哪个类使用的unsafe的。
平时用的unsafe必须用反射拿到的。
--
经典的代码:
package cn.itcast.n8.unsafe;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class Person {
private int i=0;private static sun.misc.Unsafe UNSAFE;private static long I_OFFSET;
static{
try {
Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
UNSAFE = (Unsafe)field.get(null);
I_OFFSET = UNSAFE.objectFieldOffset(Person.class.getDeclaredField("i"));
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Person person = new Person();
new Thread(()->{
while(true){
// person.i++;
boolean b = UNSAFE.compareAndSwapInt(person,I_OFFSET,person.i,person.i+1);
if(b){
System.out.println(UNSAFE.getIntVolatile(person,I_OFFSET));
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
new Thread(()->{
while(true){
// person.i++;
boolean b = UNSAFE.compareAndSwapInt(person,I_OFFSET,person.i,person.i+1);
if(b){
System.out.println(UNSAFE.getIntVolatile(person,I_OFFSET));
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
---282---