2021年12月1日30道面试题
1.ThreadLocal的作用和原理以及使用场景?
threadlocal是线程本地变量,它为每一个线程创建一个变量副本,来解决并发冲突问题
在jdk1.8以之前,每个threadlocal实例维护一个map,每个线程作为key,value保存的就是变量副本
在jdk1.8,改为每个Thread中维护一个threadlocalMap,threadlocal作为key,value保存变量副本
这样设计,threadLocalMap中的键值对数量就取决于threadlocal实例的数量,提高了访问效率。当线程被销毁,threadlocalMap也会随之销毁,减少了内存的消耗
使用场景:
spring security中,我们使用SecurityContextHolder来获取SecurityContext,
? 比如在springMVC中,我们通过RequestContextHolder来获取当前请求,
? 比如在 zuul中,我们通过ContextHolder来获取当前请求
2.内存溢出和内存泄漏
内存溢出:没有足够的内存供申请者使用
内存泄漏:内存中动态分配的内存空间由于某种原因未释放或无法释放,导致内存浪费。比如:使用完的连接没有关闭,使用完的对象没有被回收
3.线程池作用、java中有哪些线程池
线程池可以控制并发数量,实现线程的复用,也可以管理线程的生命周期
java中有四种线程池
1.cachedThreadPool:可缓存的线程池
corePoolSize的为0,maximumPoolSize为无限大,keepAliveTime为60s,超过这个线程的最大空闲时间,线程就会被销毁,线程最大数量为Integer的最大值
2.FixedThreadPool:固定线程数量的线程池
corePoolSize和maximumSize都为用户设置的值,keepAlivetime为0,最大线程数等于核心线程数
3.SingleThreadPool:单个线程的线程池
只会创建一个线程来处理任务,串行化执行任务
4.scheduledThreadPool:可调度的线程池
最大线程数是Integer的最大值,可以延迟和周期性执行任务
4.线程池的执行流程
当一个任务来了,如果有空闲的核心线程,直接使用
如果核心线程都不空闲,就将任务放入队列
如果队列满了,就会新建非核心线程来处理任务,
如果新建的非核心线程和核心线程等于最大线程数,就会触发线程池的拒绝策略
5.解释一下线程构造器的7个参数
CorePoolSize:核心线程数
MaximunPoolSize:最大线程数:核心线程+非核心线程的,只有当所有核心线程都不空闲且队列也满了,才会创建非核心线程
KeepAliveTime:非核心线程的最大存活时间,到了这个时间,非核心线程没有被使用,就会被摧毁
Unit:空闲时间单位,是枚举类型(HOURS,MINUTES)
WorkQueue:是一个BlockingQueue阻塞队列,超过核心线程的任务会进入队列排队
ThreadFactory:创建线程的工厂,我们可以自己实现线程的创建
Handler:饱和处理机制,拒绝策略,当任务数超过最大线程数+队列中任务数,则执行饱和处理机制
6.为什么要使用线程池
1.可以减少线程的创建和销毁,每个线程可以复用,提高效率
2.可以根据系统的承受能力,调整线程池中工作的线程数量,减轻服务器压力
7.数据结构有哪些?
根据逻辑结构分:
集合:一群没有关系的数据
线性结构:数据之间存在一对一的关系:如队列,栈、链表
树形结构:数据之间存在一对多的关系,如二叉树,多叉树
图形结构:数据之间存在多对多的关系
根据物理结构分:
顺序储存结构:用一组连续的内存空间来依次储存线性表的元素,如数组
链接存储结构:用任意的内存空间来储存线性表中的元素,不要求相邻的元素物理位置也相邻
索引储存结构:对节点建立索引,通过索引快速找到数据
散列存储结构:将元素的储存位置和关键字建立联系,又叫hash存储
8.数组和链表在存储结构上有什么区别
数组的存储需要连续的内存空间,而链表则不需要连续的内存空间,它的存储空间可以是任意位置,因为链表中的每一个元素都保存了相邻元素的指针,但链表容易造成内存碎片化
9.为什么链表容易造成内存碎片化?
因为链表的元素储存位置在物理位置上不是连续的,它是动态的分配内存空间,不是像数组一样会提前申请一块连续的内存空间
10.什么是散列储存(Hash储存),什么是哈希冲突,怎么解决
散列储存就是通过将数据的关键字key通过一个函数计算出数据存放的位置,后面要找这个数据,还是通过该函数计算出数据存放的位置来寻找
哈希冲突就是两个不相同的数据计算出了在同一张hash表中相同的位置(hash值相同,或者下标相同),解决方案可以将两个数据指向同一个链表中,也可以把冲突的hash值再进行计算,直到不冲突为止
还可以换一种哈希算法重新计算hash值
11.时间复杂度
时间复杂度是用来衡量算法执行时间的长短
在哈希表中找一个元素就是O(1)
访问数组的第n个元素是O(1)
访问链表的n个元素就是O(n)
二分搜索的最好情况是O(1),最坏情况是O(lgn)
一次for循环是O(n)
两次是O(n2) 三次是O(n3)
12.java中有哪些是线性结构?
数组、链表、栈(先进后出)(数组栈和链栈)、队列(先进先出)(数组队列和链式队列)、特殊的线性结构String Stringbuffer Stringbuilder
13.树形结构和线性结构的优势?
14.说一下树的分类以及优缺点
分为二叉树和多叉树
二叉树的任意节点最多允许有两个子节点,分为:二叉查找树(二叉排序树、二叉搜索树),平衡二叉树、红黑树(自平衡二叉查找树)、赫夫曼树
多叉树分为:b树、b+树等等
二分排序树:是有序的二叉树,任意节点左边的子节点小于右边的子节点,二分排序树查找数据就相当于二分查找法,它查找性能很高,但是有可能会倾斜而变成链表结构
平衡二叉树:左右两颗子树高度的绝对值不超过1,是为了解决二分排序树倾斜变成链表,每次进行添加或者删除操作后,都会进行重排序,因此添加和删除性能较低
红黑树:是自平衡二叉查找树,它是根据黑色节点的个数和红黑色节点之间的联系来保证树的平衡,红黑树和平衡二叉树在添加和删除操作中,为了保证平衡,都会进行左旋和右旋,不同的是红黑树还会改变节点的颜色,红变黑或者黑变红。在删除和添加操作中,红黑树的旋转次数要少于平衡二叉树,所以一般会优先选用红黑树