1、怎么判断环形链表
使用快慢指针:创建两个指针,同时指向这个链表的头节点,然后开始循环,指针1每次移动一个结点,指针2每次移动两个节点,然后比较两个节点是否相同,如果相同则判断出链表有环
使用哈希表缓存:创建一个以结点ID为key的HashSet集合,用来存储曾经遍历过的节点。从头节点开始遍历,如果发现HashSet中已经存在节点ID的key,则表示有环
2、HashTable和ConcurreentHashMap的区别
HashTable是底层数组+链表实现,无论是key还是Value都不能为null,线程安全,实现线程安全的方式是在修改数据时锁住整个HashTable,效率低。
ConcurrentHashMap:底层采用数组+链表实现,线程安全;主要是把整个Map分为N个Segment,可以提供相同的线程安全;
HashTable的synchronized是针对整张Hash表的,即每次锁住整张表让线程独占
ConcurrentHashMap允许多个修改操作并发进行,其关键在于使用了锁分离技术。
3、HashMap的底层原理,put和get的原理
put():首先将k,v封装到Node对象中;它的底层会调用k的hashCode()方法得出hash值;通过哈希表函数将hash值转换成数组的下标,下标位置上如果没有任何元素,就把Node添加到这个位置上。如果这个下标对应的位置上有链表,此时,就会拿着k和链表上每个节点的k进行equals。如果所有的equals方法返回都是false,那么这个新节点将被添加到链表末尾。如果其中有一个equals返回了true,那么这个节点的value将会被覆盖。
get():先调用k的hashCode()方法得出哈希值,并通过哈希算法转换成数组的下标;通过这个数组下标,快速定位到某个位置上。如果这个位置上什么都没有则返回Null。如果这个位置上有单向链表,那么它就会拿着参数K和单向链表上的每一个节点的K进行equals,如果所有的equals方法都返回了false,则get方法返回Null。如果其中一个节点的k和参数的K进行equals反悔了ture,就返回这个节点的value。
4、Java怎么实现多线程
1)继承Thread类
2)实现Runnable接口
3)使用Executor框架实现多线程
5、Java有哪些线程池
1)newCachedThreadPool:用来创建一个可以无限扩大的线程池,适用于负载较轻的场景,执行短期异步任务。(可以使得任务快速得到执行,因为任务事件执行短,可以很快结束,不会造成CPU过度切换)
2)newFixedThreadPool:创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化,适用于负载较重的场景,对当前线程数量进行限制(保证线程数量可控,不会造成线程过多,导致系统负载更为严重)
3)newSingleThreadExecutor:创建一个单线程的线程池,适用于需要保证顺序执行各个任务
4)newScheduledThreadPool:适用于执行延时或者周期性任务
6、CAS的使用场景
在线程竞争不激烈的时候使用CAS
线程数量多,执行时间短使用
7、Java线程安全
1)使用synchronized锁
2)手动使用Lock锁
3)使用线程安全的容器比如HashTable和ConcurreentHashMap
4)使用线程控制命令wait(),notify(),notifyAll()等
8、SpringMVC执行流程
用户发起请求给前端控制器,前端控制器请求Handler给HandlerMapping(控制器映射器),Mapping返回一个处理器执行链,再请求执行给控制器适配器找到合适的控制器执行,返回一个modelAndView,再去找视图解析器解析,返回view,最后渲染视图返回给用户