1、hashmap的底层设计原理以及扩容规则,是否线程安全,如何线程安全
HashMap是基于哈希表的Map接口的非同步实现。 HashMap底层就是一个数组结构,数组中的每一项又是一个链表。数组+链表结构,新建一个HashMap的时候,就会初始化一个数组。Entry就是数组中的元素,每个Entry其实就是一个key-value的键值对,它持有一个指向下一个元素的引用,这就构成了链表,HashMap底层将key-value当成一个整体来处理,这个整体就是一个Entry对象。当需要存储一个Entry对象时,会根据hash算法来决定在其数组中的位置,在根据equals方法决定其在该数组位置上的链表中的存储位置;当需要取出一个Entry对象时,也会根据hash算法找到其在数组中的存储位置, 在根据equals方法从该位置上的链表中取出Entry。JDK1.8做出了改变,使用 数组 + 链表 + 红黑树 的结构。当节点数不大于8时,还是一个链表结构,只不过插入节点时变成了 尾插法 ,当节点数大于8后,将从链表结构转化成红黑树结构。
HashMap中默认初始容量为16,默认负载因子为0.75。这里的容量是指Entry数组的长度,不是HashMap中总的元素数。当HashMap中Entry[]数组已使用容量达到负载因子*容量后,会调用resize()方法自动进行扩容,将容量扩大为原来的2倍,并重新计算元素在数组中的位置,然后将元素复制到新数组中。
HashMap是线程不安全的,HashTable、ConcurrentHashMap是线程安全的
使用
Collections.synchronizedMap
方法返回一个线程安全的HashMap集合。使用
ConcurrentHashMap
,它是专为并发环境设计的,提供了比Hashtable更高的并发级别
2、八大基本数据类型以及长度
整型: byte(占用1个字节) short(占用2个字节) int(占用4个字节) long(占用8个字节)
浮点型: float(占用4个字节)、double(占用8个字节)
字符型: char 布尔型: boolean
3、多线程创建四种方式,以及callable和runnable的区别,如何获取返回值
- 继承Thread类创建线程
- 实现Runnable接口创建线程
- 使用Callable和Future创建线程
- 使用线程池创建(使用java.util.concurrent.Executor接口)
1、最大的区别,runnable没有返回值,而实现callable接口的任务线程能返回执行结果
2、callable接口实现类中的run方法允许异常向上抛出,可以在内部处理,try catch,但是runnable接口实现类中run方法的异常必须在内部处理,不能抛出