知识点扫盲
Java基础
-
List\Map\Set是否都是Collection的子类?
-
**【String类面试题】 **补课->深入理解Java中的String
-
String str = new String("abc")到底创建了几个对象?
答:2个对象。一个对象是"abc",另一个是指向"abc"的引用对象"s"; -
你对String对象的intern()熟悉吗?
-
接口和抽象类的区别?
-
List是否可以存null,Set是否可以存null,List和Map的区别?
-
switch是否可以使用string作参数?byte?long?
-
Object中有哪些公共方法?
-
Java的四种引用?WeakReference和SoftReference的区别?
-
什么是不可变对象?final关键字
-
Runnable和Callable有什么区别?
-
Runnable不会返回结果,Callable会。
-
Object 的 hashcode 方法重写了,equals 方法要不要重写?
-
try catch finally块中return的执行顺序
- 当没有异常发生时,优先级finally>try
- 当有异常发生时,优先级finally>catch>捕获异常最外面的return
-
Java的深拷贝和浅拷贝
a. 引用拷贝和对象拷贝就是浅拷贝和深拷贝吗?
-- 不是。浅拷贝和深拷贝都属于对象拷贝。浅拷贝仅复制属性的引用而不复制属性引用所指的对象。深拷贝直接复制该属性指向的对象(即原对象和新对象的属性地址不同)。
b. 如何实现浅拷贝?如何实现深拷贝?
-- 浅拷贝:1. 实现Cloneable接口并重新clone方法。
-- 深拷贝:1. 实现Cloneable接口并重新clone方法。2. 通过序列化方式实现。
c. Objct对象的clone()方法为什么要声明为protected?
--// todo -
自动装箱:编译器调用valueOf()将原始类型值转成对象;
-
自动拆箱:编译器通过类似intValue(),doubleValue()这些方法将对象转换成原始类型值。
-
Java中的++操作符线程安全吗?
-- 线程不安全。
-- 解决办法:加锁 -
什么是ThreadLocal?
-
为使用该变量的每个线程维护一份独立的变量副本,每个线程都可以改变自己的副本,而不影响其他线程的副本;
-
线程有哪些状态?以及5大状态之间的流转?
-
Java NIO常用的三个类
-
同步IO和异步IO
-
IO操作分2个步骤,请求IO和实际IO,同步IO和异步IO的主要区别是第二步是否阻塞。
-
若实际IO操作阻塞请求进程(即请求进程轮询查看IO是否就绪),则为同步IO。
-
若实际IO操作并不阻塞请求进程(即由OS进行实际IO操作并返回结果),则为异步IO。
-
阻塞IO和非阻塞IO
-
阻塞和非阻塞IO的区别在于第一步是否阻塞。
-
若发起IO请求后,请求线程一直等待时间实际IO操作完成,则为阻塞IO。
-
若发起IO请求后,请求进程返回而不等待,则为非阻塞IO。
-
BIO、NIO、AIO
-
BIO-同步阻塞
-
NIO-同步非阻塞
-
AIO-异步非阻塞
-
-
java线程阻塞调用wait()和sleep()区别和联系,还有函数yield,notify等的作用?
-
区别主要看2点:1. CPU是否继续执行。2.锁是否释放掉。
-
sleep是Thread的方法。
-
暂停当前线程的执行,将CPU让给其他线程,保持对象锁直到睡眠结束。如果外包层有Synchronize,那么
-
wait是Object的方法。
-
调用对象的await方法。会导致当前线程放弃对象的锁(线程暂停执行),进入对象的等待池(wait pool),只有调用对象的notify方法或notifyALl(),才能唤醒等待池中的线程进入锁池(Lock pool),如果线程重新获得对象的锁,就会进入就绪状态。
-
【List、Map、Set总结】
-
List中的元素:有序、可重复、可为NULL;
-
Set中的元素:无序、不可重复、只有一个NULL;
-
Map中的元素:无序、Key不重,Value可重、可一个NULL Key,多个NULL值;
-
JMM中对共享变量的读写原理;
J.U.C
-
说一说对轻量级锁CAS的理解?
-
原理
-
在 CAS 中有三个参数:内存值 V、旧的预期值 A、要更新的值 B ,当且仅当内存值 V 的值等于旧的预期值 A 时,才会将内存值V的值修改为 B ,否则什么都不干。
-
CPU如何实现多处理器下的原子操作?
-
总线加锁
-
缓存加锁
-
地位:
-
CAS是J.U.C的基石;整个AQS同步组件、Atomic原子类操作都是基于CAS实现的。
-
Unsafe是CAS的核心类;--提供了硬件级别的原子操作。
-
缺点:
-
循环时间太长;
-
只能保证对一个共享变量的原子操作;
-
ABA问题;--如何解决?Java提供AtomicStampedReference来解决#版本号#;
-
说一说对于AQS和CLH的理解?
-
CLH(队列锁)是一个FIFO的同步队列。AQS依赖CLH来完成同步状态的管理。
-
AQS(队列同步器)使用Template设计模式实现,使用者只要继承并重写指定方法。
-
AQS队列同步器是如何实现线程同步的?
-
独占式获取和释放同步状态;--void acquire(int arg)/boolean release(int arg)
-
在获取同步状态的时候,会维护一个同步队列,如果获取失败的线程会通过CAS的方式加入到队列中并进行自旋。
-
被移除队列的条件是:前驱节点是头节点并且成功获取同步状态。
-
共享式获取和释放同步状态;-- void acquireShared(int arg)/boolean releaseShared(int arg)
-
独占式和共享式的主要区别是:同一时刻是否有多个线程获取到同步状态。
-
tryRelease()必须线程安全的释放,一般通过CAS来保证。
-
超时获取同步状态; --
-
涉及概念:
-
响应中断与不响应中断
-
可重入与不可重入的区别?
-
可重入:任何线程在获取到锁之后,可以再错获取到锁而不被阻塞的特性。
-
sychronized支持可重入:如递归方法用synchronized修饰,会连续多次加锁。
-
公平锁与非公平锁
-
公平锁:等待时间越久的线程,优先获取锁。能减少“饥饿”的发生。
-
AQS如何实现线程的等待与唤醒?-- LockSupport
-
如何实现一个Lock?
-
写一个死锁例子 --可以使用CountDownLatch写一个死锁例子
-
说一说对于重量级锁Synchronized的理解?
-
说一说对于线程池的理解?
-
CyclicBarrier和CountDownLatch的区别,内部实现有何不同**?**分别在什么场景下使用?join和CountDownLatch有什么区别? | | CyclicBarrier | CountDownLatch | | --- | --- | --- | | 原理 | | 调用countDown()进行减1计算,调用awit()方法进行阻塞。 | | 场景 | 1. Boss要开会,需要N个人都到了才开始。
-
适用于多线程计算,获取最终结果。 | 电商详情页由很多模块获取,彼此之间没啥关联,为提供响应时间,可以并发获取数据,全部获取完毕后返回,这种场景可以使用CDL | | 区别 | 1. 可以条用reset()重置;适用更加复杂的场景,如果发生计算错误,可以重置。
-
提供了更多方法,例如getNumberWaiting获取阻塞线程数量; | 1. 计数器不能复用。 |
-
讲讲独占锁 ReentrantLock 原理?
-
Lock和Synchronized的区别?他们都是可重入锁吗?哪个效率更高?
-
谈谈读写锁 ReentrantReadWriteLock 原理?
-
ReentrantReadWriteLock锁降级:写锁降级为读锁
-
ReentrantReadWriteLock不支持锁升级。
-
讲讲对JUC 中回环屏障 CyclicBarrier 的使用?
-
Semaphore 的内部实现是怎样的?
-
适用于(单机)流量控制。
-
并发组件CopyOnWriteArrayList 是如何通过写时拷贝实现并发安全的 List?
-
线程间交换数据Exchange -
无 -
LockSupport
-
Condition
线程、进程相关问题
-
说说线程、进程、协程之间的区别?
-
进程是OS分配资源的最小单元,线程是OS调度的最小单元;(进程是最小的资源管理单元;线程是最小的执行单元)
-
一个程序至少有一个进程,一个进程至少有一个线程;
-
联系:线程从属于进程,是程序的实际执行者。线程拥有自己的栈空间
-
线程不同状态之间的切换是由谁完成的?是JVM吗?
-
不是。JVM通过TCB(Thread Control Block)模块来改变下线程的状态,这一过程需要消耗CPU资源;
-
线程进程的痛点(协程和进程线程之间有什么关系?):线程之间如何进行协作?
-
最经典的例子:生产者/消费者模型;
-
生产者/消费者模型性能不高原因?
-
涉及到了同步锁;
-
涉及线程上下文的切换;
-
如何解决?-->协程
-
什么是协程?
-
比线程更轻量级的一种存在;
-
一个线程拥有多个协程;
-
协程的好处?-- 协程的开销远远小于线程。协程不被OS所管理,完全有程序控制(在用户态执行);
-
Java中原生语法没有实现协程;
-
你了解守护线程吗?它和非守护线程有什么区别?
-
什么是多线程上下文的切换?
-
创建线程的2种方式是什么?他们有什么区别?
-
Thread类中的run和start有什么区别?
-
怎么检测一个线程是否有对象监视器?
-
死锁与活锁的区别?饥饿与死锁的区别?产生死锁的条件?
-
concurrenthashmap和hashmap的区别,chm的实现原理,你在什么场景下用到chm,为什么,我说了多线程查询数据,put可能覆盖,或者hashmap的扩容可能产生死链
-
Spring了解么,问我了解五大组件不,不了解,说了ioc和aop。然后问我分别怎么实现的,使用xml和注解配置实现类有什么区别,怎么解析它们的数据;
大数据排序问题
-
如何快速对一个2亿数据的List进行排序;
-
10G的数据,在2G内存的单台机器上排序的算法;
并发问题
【HashMap问题集合】
-
底层实现?put和get的原理?
-
底层实现使用的是:数组+链表的数据结构。
-
put原理:(扩容机制)
-
根据key获取相应的Hash值:int hash = hash(key.hash.hashcode())
-
根据(Hash值和数组长度)确定引用位置:int i = indexFor(hash,table.length)。如果不同的key映射到相同的位置,就放入链表。
-
get原理:
-
获取对应数据位置;
-
遍历该数组所在链表:key.equals();
-
HashMap和TreeMap的区别?和HashTable有什么区别?和ConcurrentHashMap的区别
-
和TreeMap的区别:
-
和HashTable区别:
-
线程安全:不安全;线程安全
-
负载因子:16;11
-
NULL值: KV都允许为NULL;允许;
-
和ConcurrentHashMap区别:
-
HashMap遇到Hash碰撞的时候,除了拉链法解决,还是什么其他的方法吗?
-
开放定址法
-
线性探测再散列
-
再Hash
-
HashMap的负载因子是多少?达到负载因子扩容还是没达到就扩容了?ConncurrentHashMap呢?
- 0.75
- 为什么ConcurrentHashMap和HashTable都是线程安全的,但是前者性能更高?
- 因为2者使用的锁的粒度不同。ConcurrentHashMap使用的是分段锁。
- JDK1.7和JDK1.8的HashMap有什么区别?
-
为了加快查询效率,JDK1.8的HashMap引入了红黑树结构。
-
当链表长度>8时,该链表就会改成红黑树结构,从而加快查询效率。
计算机网络
-
tcp三次握手、四次挥手;为什么握手是三次?为什么要四次挥手?
-
两次握手会出现什么问题?
-
三次握手主要目的是:防止出现请求超时而导致脏连接;
-
如果两次握手:如果有超时的请求,而Server返回ACK确认报文,但是Client因为是超时的请求而没有处理,就会导致Server白白建立连接;
-
为什么握手只要3次,而挥手需要4次?
-
因为Server需要把没有传完的数据传完;
-
为什么TIME_WAIT状态需要经过2MSL(最大报文段生存时间)才返回CLOSE状态?
-
为了保证Client发送的最后一个ACK报文能够到达Server;
-
允许老的重复的分节在网络中消失;
-
什么是滑动窗口机制?什么是慢启动?什么是拥塞避免?
-
说一说OSI七层模型;每一层都干了哪些?
-
说一说TCP/IP四层模型;
-
请简述tcp和udp的区别?
-
连接。-- TCP面向连接;UDP无连接;
-
可靠服务。--TCP提供可靠服务;UDP提供尽最大努力服务;
-
字节字符。--TCP面向字节流;UDP面向字符流;
-
点对点。--TCP是点对点。UDP支持一对多、多对一、多对多;
-
效率。--TCP传输速率慢,安全。UDP传输快,不安全;
-
怎样使不可靠的udp变得可靠?
-- RUDP。
-- 重传。传送门:www.infoq.cn/article/how… -
TCP协议如何保证可靠性?juejin.im/post/5b7be0…
-
校验和。
-
目的是检测数据传输过程中的任何变化。
-
停止等待协议。
-
基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后再发下一个分组。
-
无差错情况;
-
出现差错情况(超时重传);
-
确认丢失|确认迟到;
-
自动重传ARQ协议
-
指超过一段时间仍没有收到确认,就重传之前发送过的分组;
-
每发送完一个分组,就设置一个超时计时器;
-
连续ARQ协议** **--提高信道利用率
-
发送方维持一个发送窗口,凡是在这个窗口之内的分组都可以连续发送出去,不需要停止等待对方确认。
-
流量控制.
-
TCP使用滑动窗口机制实现流量控制;
-
为了控制发送方速率,保证接收方来得及接收;
-
接收方可以通过发送ACK报文中的窗口字段,可以控制发送方窗口大小,从而影响发送方速率;
-
拥塞控制
-
参照下面8
-- 流量控制和拥塞控制的区别
-
拥塞控制是防止过多的数据注入到网络中,可以使网络中的路由器或链路不致过载,是一个全局性的过程。
-
流量控制是点对点通信量的控制,是一个端到端的问题,主要就是抑制发送端发送数据的速率,以便接收端来得及接收。
- 经典的拥塞算法有哪几个部分?
慢开始、拥塞避免、快重传、快恢复;
-
慢开始。
-
如果刚开始就发送大量数据,就会导致网络拥堵,就会产生大量丢包,大量重传,影响效率;
-
不要一开始就发送大量数据,先嗅探下网络的拥塞程度,从小到大增大cwnd窗口;
-
拥塞避免.
-
当拥塞窗口 cwnd 达到一个阈值时,窗口大小不再呈指数上升,而是以线性上升,避免增长过快导致网络拥塞。
-
让cwnd窗口缓慢增长,即每经过一个往返RTT,就把发送方的cwnd值+1,而不是加倍,让拥塞窗口按线性缓慢增长;
-
快重传。
-
发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设置的重传计时器时间到期。
-
当发送方连续收到三个重复确认时,就执行“乘法减小”算法,把ssthresh门限减半。但是接下去并不执行慢开始算法。
-
快恢复。和快重传配合使用。
-
考虑到如果网络出现拥塞的话就不会收到好几个重复的确认,因此发送方现在认为网络可能没有出现拥塞。所以此时不执行慢开始算法,而是将cwnd设置为ssthresh的大小,然后执行拥塞避免算法。
-
在浏览器输入网址之后发生了什么?
-
HTTP与HTTPS区别?HTTP2.0?
-
HTTP的长短连接?
-
从HTTP1.0开始默认使用长连接;使用长连接的HTTP请求,默认会在Header添加Connection:keep-alive。
-
HTTP协议的长短连接实质是TCP协议的长短连接;
数据结构
- 快排(非递归) --要求手写
public class QuickSort {
public static void main(String[] args) {
int[] table = {38, 26, 97, 19, 66, 1, 5, 49};
quickSort(table);
for (int i = 0; i < table.length; i++) {
System.out.print(table[i] + "\t");
}
}
private static void quickSort(int[] table) {
quickSort(table, 0, table.length - 1);
}
/**
* 时间复杂度
* 最好的情况下是:O(NlogN)
* 最坏的情况下是:O(N^2)
* @param table
* @param begin
* @param end
*/
private static void quickSort(int[] table, int begin, int end) {
if (begin < end) {
int i = begin;
int j = end;
int vot = table[i];
while (i != j) {
// 尾指针向前移动
while (i < j && table[j] >= vot) {
j--;
}
if (table[j] < vot) {
table[i++] = table[j];
}
// 头指针向后移动
while (i < j && table[i] <= vot) {
i++;
}
if (table[i] > vot) {
table[j--] = table[i];
}
}
table[i] = vot;
//
quickSort(table, begin, j - 1);
quickSort(table, j + 1, end);
}
}
}
复制代码
-
链表反转-- 要求手写
-
二分查找(递归和非递归)
/**
* 二分查找[非递归实现]
*
* @param array
* @param target
* @return 返回出现在数组中的位置
*/
public static int binSearch(int[] array, int target) {
int low = 0;
int high = array.length - 1;
int mid;
while (low <= high) {
mid = (low + high) / 2;
if (array[mid] == target) {
return mid + 1;
} else if (array[mid] < target) {
low = mid + 1;
} else if (array[mid] > target) {
high = mid - 1;
}
}
return -1;
}
/**
* 二分查找[递归实现]
* 时间复杂度O(logN)
*
* @param array
* @param target
* @return
*/
public static int binSearch2(int[] array, int target, int low, int high) {
if (low <= high) {
int mid = (low + high) / 2;
if (array[mid] == target) {
return mid + 1;
} else if (array[mid] < target) {
return binSearch2(array, target, mid + 1, high);
} else {
return binSearch2(array, target, low, mid - 1);
}
}
return -1;
}
复制代码
【二叉树】
-
重建二叉树
-
层次遍历二叉树
-
之字遍历二叉树
【贪心、回朔、分治、动规、递归】
-
贪心算法思想:保证每次计算的结果都是局部最优,并且最后得到的结果是全局最优的;
-
典型算法:DFS\BFS、股票买卖
-
回朔算法思想:
-
典型算法:N皇后
-
递归
-
典型算法:跳台阶
-
动规
-
典型算法:最短路径算法
分布式
-
什么是CAP原理?什么是BASE理论?
-
强一致性和弱一致性有什么方法来实现?
-
dubbo 支持哪些通信协议?支持哪些序列化协议?说一下 Hessian 的数据结构?PB 知道吗?为什么 PB 的效率是最高的?
-
支持的通讯协议
-
dubbo
-
hession
-
rmi
-
http
-
webserivce
-
支持的序列化协议
-
hession
-
java 二进制序列化
-
json
-
SOAP协议
-
为什么protobuf是效率最高的?
-
使用了proto编译器,自动进行序列化和反序列化,效率是json和xml的20~100倍。
-
数据压缩后体积小,节约带宽。
-
zookeeper是什么?zk的性能瓶颈怎么克服?
-
MySQL主从复制怎么实现的?具体原理是什么?有什么优缺点?如何解决主从同步延时问题?
-
原理:同步bin-log日志(记录了所有sql操作)
-
主:binlog输出线程
-
从:IO线程-去主库请求binlog,并将得到的binlog写到relay log(中继)日志文件中;
-
从:SQL线程-读取relay log日志读取、解析、执行,从而实现主从一致。
-
如何解决主从同步延时问题?
-
并行复制
-
做主从之后,主挂了怎么办?
-
半同步复制
-
讲讲分布式事务?
-
重复消费怎么解决?
-
幂等机制
-
如何保证消息的可靠性传输?
-
RabbitMQ为例
-
生产者弄丢了数据
-
事务机制
-
confirm机制
-
事务机制和confirm机制最大的区别在于:事务机制是同步的,但是confirm机制是异步的。
-
RabbitMQ弄丢了数据
-
持久化机制:
-
创建Queue时设置持久化机制;
-
发送消息的时候,将消息设置为持久化;
-
消费者弄丢了数据
-
autoAck机制。
-
Kafka为例
-
顺序消费
-
让每个消费者
-
MQ消息积压了几百万条数据怎么办?
-
如何实现session共享?用redis如何实现?
-
如何设计一个高并发系统?
-
消息队列
-
缓存
-
分库分表
-
读写分离
-
如何设计一个高可用系统?
-
限流
-
熔断
-
降级
缓存
-
缓存失效场景:缓存穿透,缓存雪崩,缓存击穿;www.toutiao.com/i6662477562…
-
缓存穿透
-
概念:访问一个不存在的Key,缓存不起作用,请求直接穿透到DB,流量大时DB会挂掉;
-
解决方案:
-
布隆过滤器;--不存在的Key直接打回;
-
访问Key如果在DB没查到值,也可以将空值存到DB,但可以设置较短过期时间;
-
缓存雪崩
-
概念:大量的key设置了相同的过期时间,导致缓存在同一时间全部失效;
-
解决方案:给缓存过期时间设置一个随机值。
-
缓存击穿(缓存并发,热点Key)
-
概念:在高并发场景下,一个存在的key即将过期,大量请求直接打到DB;
-
解决方案:
-
使用互斥锁:redis的setnx。
-
优点:简单,保证数据一致性;
-
缺点:死锁风险;
-
“物理不过期,逻辑过期”:异步线程构建缓存
-
优点:不会阻塞线程;
-
缺点:不能保证数据一致性;
-
缓存雪崩和缓存击穿的区别?
-- 前者针对多个Key,后者针对一个Key。 -
redis数据结构有哪些?
-
string list set hash zset
-
reids线程模型?
-
如何使用Redis来实现分布式锁?
-
setnx
-
Redis的并发竞争问题如何解决?
-
Redis持久化的几种方式,优缺点是什么,怎么实现的?
-
aop rdf
-
Redis的缓存失效策略?
-
Redis集群,高可用,原理?
-
Redis缓存分片?
-
Redis的数据淘汰策略?(数据淘汰机制)
-
redis队列应用场景?
-
分布式使用场景(储存session)?
Linux
- awk sed
非典型面试问题
-
为什么阿里巴巴禁止把SimpleDateFormat定义为static类型的?
-
解决方案
-
加锁
-
使用JDK1.8的DateTimeFormatter
-
使用ThreadLocal
- XXX
框架
【Spring】
- 动态代理的好处?使用场景?
- 好处:实现无侵入的代码扩展。也就是方法增强。
- 使用场景:日志管理
- spring的实现方式
- jdk动态代理,本质是反射,前提是被代理的对象至少实现一个接口。
- 如果没有实现任何接口,则使用cglib代理。
- cglib代理的前提是:被代理对象的方法不能是final修饰,因为final修饰的方法无法被覆盖。
- cglib代理的本质是:使用asm动态生成字节码,性能比jdk强。
- 原理是:在运行期间生成被代理对象的扩展子类。
【mybatis应用和源码解析】
- mybatis优缺点、spring 与mybatis 集成
- Config、Sql配置、Mapper配置、有几种注册mapper的方法,优先级如何?
- mybaits的一级缓存、二级缓存、mybatis的二级缓存为什么是鸡肋?
- 通用mapper的实现、mybaits编写sql语句的三种方式
- @MapperScan的源码分析?mapperScan如何生效的?
- mybatis如何扩展spring的扫描器的、mybatis扫描完之后如何利用FactoryBean的?
- mybaits底层如何把一个代理对象放到spring容器中?用到了spring的哪些知识?
- mybaits和spring的核心接口ImportBeanDefinitionRegistrar之间千丝万缕的关系
- 从原理来说明mybaits的一级缓存为什么会失效?spring为什么把他失效?有没有办法解决?
- 从mybatis来分析mybatis的执行流程、mybaits的sql什么时候缓存的?缓存在哪里?
- mybaits当中的方法名为什么需要和mapper当中的id一致?从源码来说明
安全
项目
- 比较复杂的业务逻辑讲一下?
- 遇到很难解决的问题和突破收货?
- 价值较高的项目,从架构设计到部署捋一遍。
题库