1Java 基础
1、HashMap的源码,实现原理,JDK8中对HashMap做了怎样的优化。
jdk1.7实现:
源码是采用Node数组方式实现,node即链表节点,故jdk1.7中hashMap是采用数组+链表方式实现,hashMap在进行初始化时,数组长度默认为16,当对key进行hash运算取数组下标发现该下标已存在时,会针对此key重新生成一个node节点然后追加到数组下标已存在对应的节点后面
jdk1.8实现:
原理大部分和1.7类似,最大的区别在于设置了链表默认长度,当链表长度大于8时,会转化为红黑树存储节点数据,以提升其查找效率
2、HaspMap扩容是怎样扩容的,为什么都是2的N次幂的大小
- 空参数的构造函数:以默认容量、默认负载因子、默认阈值初始化数组。内部数组是空数组。
- 有参构造函数:根据参数确定容量、负载因子、阈值等。
- 第一次put时会初始化数组,其容量变为不小于指定容量的2的幂数。然后根据负载因子确定阈值。
- 如果不是第一次扩容,则新容量=旧容量*2,新阈值=新容量*负载因子
为什么都是2的N次幂?性能优化吧,估计跟计算机的存储结构以及其使用的取模运算有关
3、HashMap,HashTable,ConcurrentHashMap的区别。
hashMap:内部采用数组+链表(1.7)或数据+链表+红黑树实现(1.8),线程不安全
HashTabel:内部结构数组+链表,线程安全,对里面的所有存取值方法采用了synchronize加锁方式
ConcurrentHashMap:
jdk1.7:采用分段锁机制,即基本结构为ReetrantLock+segement+数组+链表,其大概思想为将底层数组进行分段加锁,相比于hashTable,锁粒度相对较小,hashTable锁全局数据,ConcurrentHashMap则锁部分数据,需要2次hash运算才能定位到该元素,第一次定位segement,第二次定位segement里的链表节点头部,segement继承ReetrantLock进行加锁,并发度为segement个数,segement扩容时对其他segement不造成影响,其get方法无需加锁,采用volatile保证对其他线程可见
jdk1.8:采用Synchronized+CAS+数组+链表+红黑树,相比于jdk1.7锁粒度更小,只锁链表头部节点,节点内部(node)的val和next都是volatile保证其可见性,替换,赋值都采用CAS
因为其锁链表头部节点,不影响其他元素读写,所以锁粒度更小,并发时效率也更高,扩容时阻塞所有读写操作,并发扩容,读操作无需加锁,采用volatile修饰node的val和next是保证读写线程对该变量可见,数组用volatile修饰,是保证扩容时被读线程感知
4、极高并发下HashTable和ConcurrentHashMap哪个性能更好,为什么,如何实现的。
ConcurrentHashMap,锁粒度更小,写并发效率更高
5、HashMap在高并发下如果没有处理线程安全会有怎样的安全隐患,具体表现是什么。
多线程put时可能会导致get无限循环,具体表现为CPU使用率100%; 原因:在向HashMap put元素时,会检查HashMap的容量是否足够,如果不足,则会新建一个比原来容量大两倍的Hash表,然后把数组从老的Hash表中迁移到新的Hash表中,迁移的过程就是一个rehash()的过程,多个线程同时操作就有可能会形成循环链表,所以在使用get()时,就会出现Infinite Loop的情况
写覆盖即多线程put时可能导致元素丢失 原因:当多个线程同时执行addEntry(hash,key ,value,i)时,如果产生哈希碰撞,导致两个线程得到同样的bucketIndex去存储,就可能会发生元素覆盖丢失的情况
6、java中四种修饰符的限制范围。
懒得写
7、Object类中的方法。
equals、hashCode等
8、接口和抽象类的区别,注意JDK8的接口可以有实现。
9、动态代理的两种方式,以及区别。
jdk动态代理:
Proxy:Proxy是所有动态代理的父类;它提供了一个静态的方法创建代理的Class对象来配置生成代理类Class文件的方法与参数,主要就是通过Proxy.newProxyInstance(类加载器,类实现的接口,InvocationHandler实现类),返回Object类型,通过接口类型强转换即可使用代理类;
InvacationHandler:每个动态代理实例都有一个关联的InvocationHandler;被代理类的代理方法被调用时,方法将被转发到InvocationalHandler的invoke方法执行
cglib动态代理:
Enchancer:来指定要代理的目标对象;实际处理逻辑的对象;最终通过create()方法得到代理对象,对这个对象的非final()方法的调用都会转发给代理对象;
bMethodInterceptor:动态代理的方法调用都会转发到intercept()上进行增强
10、Java序列化的方式。
Java原生序列化
只要让类实现 Serializable 接口就行,序列化具体的实现是由ObjectOutputStream和ObjectInputStream来实现的
JSON序列化
JSON 可能是我们最熟悉的一种序列化格式了,JSON 是典型的 Key-Value 方式,没有数据类型,是一种文本型序列化框架,JSON 的具体格式和特性,网上相关的资料非常多,这里就不再介绍了。他在应用上还是很广泛的,无论是前台 Web 用 Ajax 调用、用磁盘存储文本类型的数据,还是基于 HTTP 协议的 RPC 框架通信,都会选择 JSON 格式
11、传值和传引用的区别,Java是怎么样的,有没有传值引用。
前者传的是真实内存里的值,后者传的是另外一个对象的地址,对于值引用,赋值运算符会直接改变变量的值,原来的值被覆盖掉,对于传引用,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。但是原来的对象不会被改变
12、一个ArrayList在循环过程中删除,会不会出问题,为什么。
肯定会啦,
异常:
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
list执行的remove方法:
public boolean remove(Object o) {
if (o == null) {
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
// 示例中调用的是此处的 fastRemove
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
// 此处 modCount + 1
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index+1, elementData, index,
numMoved);
elementData[--size] = null; // clear to let GC do its work
}
改变了modCount值,导致判断出现异常
Iterator中的remove方法:
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
删除元素时expectedModCount也要做相应变更
2JVM
1、JVM的内存结构。
2、JVM方法栈的工作过程,方法栈和本地方法栈有什么区别。
3、JVM的栈中引用如何和堆中的对象产生关联。
4、可以了解一下逃逸分析技术。
5、GC的常见算法,CMS以及G1的垃圾回收过程,CMS的各个阶段哪两个是Stop the world的,CMS会不会产生碎片,G1的优势。
6、标记清除和标记整理算法的理解以及优缺点。
7、eden survivor区的比例,为什么是这个比例,eden survivor的工作过程。
8、JVM如何判断一个对象是否该被GC,可以视为root的都有哪几种类型。
9、强软弱虚引用的区别以及GC对他们执行怎样的操作。
10、Java是否可以GC直接内存。
11、Java类加载的过程。
12、双亲委派模型的过程以及优势。
13、常用的JVM调优参数。
14、dump文件的分析。
15、Java有没有主动触发GC的方式(没有)。
3数据结构与算法
1、B+树
2、快速排序,堆排序,插入排序(八大排序算法)
3、一致性Hash算法,一致性Hash算法的应用
4多线程
1、Java实现多线程有哪几种方式。
2、Callable和Future的了解。
3、线程池的参数有哪些,在线程池创建一个线程的过程。
4、volitile关键字的作用,原理。
5、synchronized关键字的用法,优缺点。
6、Lock接口有哪些实现类,使用场景是什么。
7、可重入锁的用处及实现原理,写时复制的过程,读写锁,分段锁(ConcurrentHashMap中的segment)。
8、悲观锁,乐观锁,优缺点,CAS有什么缺陷,该如何解决。
9、ABC三个线程如何保证顺序执行。
10、线程的状态都有哪些。
11、sleep和wait的区别。
12、notify和notifyall的区别。
13、ThreadLocal的了解,实现原理。
5分布式
1、分布式事务的控制。分布式锁如何设计。
2、分布式session如何设计。
3、dubbo的组件有哪些,各有什么作用。
4、zookeeper的负载均衡算法有哪些。
5、dubbo是如何利用接口就可以通信的。
6框架相关
1、SpringMVC的Controller是如何将参数和前端传来的数据一一对应的。
2、Mybatis如何找到指定的Mapper的,如何完成查询的。
3、Quartz是如何完成定时任务的。自定义注解的实现。
4、Spring使用了哪些设计模式。Spring的IOC有什么优势。
5、Spring如何维护它拥有的bean。
6、一些较新的东西JDK8的新特性,流的概念及优势,为什么有这种优势。
7、区块链了解如何设计双11交易总额面板,要做到高并发高可用