基础篇
基本功
- 面向对象的特征
- final, finally, finalize 的区别
- 重载和重写的区别
- 说说反射的用途及实现
- equals 与 == 的区别
数据结构
集合
- List 和 Set 区别
- List 和 Map 区别
- Arraylist 与 LinkedList 区别
- ArrayList 与 Vector 区别
- HashMap 和 Hashtable 的区别
- HashSet 和 HashMap 区别
- HashMap 和 ConcurrentHashMap 的区别
- HashMap 的工作原理及代码实现
- ConcurrentHashMap 的工作原理及代码实现
- HashMap是如何扩容的
- HashMap如何避免key碰撞
- HashMap死循环问题
进阶篇
网络
- 讲讲TCP/IP
- 讲讲TCP、UDP、IP
- TCP三次握手、四次握手
IO
-
Java中IO流的分类
-
NIO、BIO、AIO
See: www.cnblogs.com/zedosu/p/66…
- BIO:同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。
- NIO:同步非阻塞式IO,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
- AIO(NIO 2.0):异步非阻塞式IO,服务器实现模式为一个有效请求一个线程,客户端的IO请求都是由OS先完成了再通知服务器应用去启动线程进行处理。
线程
References Java线程模型
-
说说 CountDownLatch 原理
CountDownLatch是同步工具类之一,可以指定一个计数值,在并发环境下由线程进行减1操作,当计数值为0之后,被await方法阻塞的线程将会唤醒,实现线程间的同步。
-
说说 CyclicBarrier 原理

CyclicBarrier 字面意思是可循环(Cyclic)使用的屏障(Barrier)。它要做的事情是让一组线程到达一个屏障(同步点)时被阻塞,直到最后一个线程到达屏障时候,屏障才会开门。所有被屏障拦截的线程才会运行。
CyclicBarrier是由ReentrantLock可重入锁和Condition共同实现的。
-
说说 Semaphore 原理
-
说说 Exchanger 原理
-
说说 CountDownLatch 与 CyclicBarrier 区别
| CountDownLatch | CyclicBarrier |
|---|---|
| 减计数方式 | 加计数方式 |
| 计算为0时释放所有等待的线程 | 计数达到指定值时释放所有等待线程 |
| 计数为0时,无法重置 | 计数达到指定值时,计数置为0重新开始 |
| 调用countDown()方法计数减一,调用await()方法只进行阻塞,对计数没任何影响 | 调用await()方法计数加1,若加1后的值不等于构造方法的值,则线程阻塞 |
| 不可重复使用 | 可重复利用 |
CountDownLatch 强调的是一个线程(或多个)需要等待另外的n个线程干完某件事情之后才能继续执行。
举个例子:有五个人,一个裁判。这五个人同时跑,裁判开始计时,五个人都到终点了,裁判喊停,然后统计这五个人从开始跑到最后一个撞线用了多长时间。
我们实现代码的思路可能是这样:main线程是裁判,5个Worker是跑步的,运动员先准备,裁判喊跑,运动员才开始跑(这是第一次同步,对应begin)。5个人谁跑到终点了,countdown一下,直到5个人全部到达,裁判喊停(这是第二次同步,对应end),然后算时间。
CyclicBarrier强调的是n个线程,大家相互等待,只要有一个没完成,所有人都得等着。
-
ThreadLocal 原理分析
用于防止对可变的单实例变量或全局变量进行共享
-
讲讲线程池的实现原理
-
线程池的几种方式与使用场景
锁机制
- AQS详解

AQS是AbstractQueuedSynchronizer的简称。AQS提供了一种实现阻塞锁和一系列依赖FIFO等待队列的同步器的框架。AQS为一系列同步器依赖于一个单独的原子变量(state)的同步器提供了一个非常有用的基础。子类们必须定义改变state变量的protected方法,这些方法定义了state是如何被获取或释放的。
See www.cnblogs.com/waterystone…
-
说说线程安全问题
某个属性是被多线程共享的资源,同时多线程有读写操作,就有可能(注意是有可能)存在线程安全问题。
即使是有多线程对同一个共享资源都有读写,也不能笼统的说就一定存在线程安全问题
要考虑线程安全问题并不代表一定就有线程安全问题。仿佛有点矛盾。判断存不存在线程安全问题,还要根据业务特点和发生问题导致的结果来判断。
-
volatile 实现原理
如果一个字段被声明成volatile,java线程内存模型确保所有线程看到这个变量的值是一致的。这个就是所谓的“可见性”,就是一个线程修改了,其他线程能知道这个操作,这就是可见性。如何实现的呢?volatile修饰的变量在生成汇编代码的时候,会产生一条lock指令,lock前缀的指令在多核处理器下会引发两件事情:
- 将当前处理器缓存行的数据写回到系统内存;
- 这个写回内存的操作会使得在其它cpu里缓存了该内存地址的数据无效。
-
synchronized 实现原理
synchronized是用java的monitor机制来实现的,就是synchronized代码块或者方法进入及退出的时候会生成monitorenter跟monitorexit两条命令。线程执行到monitorenter时会尝试获取对象所对应的monitor所有权,即尝试获取的对象的锁;monitorexit即为释放锁。
-
CAS 乐观锁
-
乐观锁的业务场景及实现方式
-
ABA 问题
核心篇
数据存储
-
MySQL 索引使用的注意事项
-
分库与分表带来的分布式困境与应对之策
-
说说 SQL 优化之道
-
负向条件(where != 条件)不能使用索引,可以优化为
in查询; -
Like 模糊查询左匹配不能使用索引, 只有右匹配能使用索引;
-
数据区分度不大的字段不宜使用索引,如:性别只有男,女,每次过滤掉的数据很少,不宜使用索引;
-
在属性上进行计算不能命中索引;
其他实践 See www.jianshu.com/p/906fd3ca8…
-
-
如何避免死锁:
- 以固定的顺序访问表和行;
- 大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小;
- 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率;
- 降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁;
- 为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增大。
-
数据库索引的原理
-
BTREE与HASH索引的区别, 为什么要用 BTREE索引
Hash 索引只能够用于使用 = 或者 <=> 运算符的相等比较(但是速度更快)。Hash 索引不能够用于诸如 < 等用于查找一个范围值的比较运算符;
B-tree 索引可以用于使用 =, >, >=, <, <= 或者 BETWEEN 运算符的列比较。如果 LIKE 的参数是一个没有以通配符起始的常量字符串的话也可以使用这种索引。
-
聚集索引与非聚集索引的区别
聚集索引:数据行的物理顺序与列值(一般是主键的那一列)的逻辑顺序相同,一个表中只能有一个聚集索引。Mysql中聚集索引就是主键索引,如果没有主键,系统会自动创建一个隐含列作为表的聚集索引。
非聚集索引:该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同,一个表中可以有多个非聚集索引。
-
limit 20000 加载很慢怎么解决
-
选择合适的数据存储方案
-
聊聊 MongoDB 使用场景
-
聊聊 ElasticSearch 使用场景
-
倒排索引
-
事务隔离级别
-
未提交读(Read uncommitted)
-
已提交读(Read committed [RC]):只能读取到已经提交的数据
-
可重复读(Repeatable read [RR]):在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别
-
可串行化(Serializable)
-
我们较常用的是RC和RR
References
缓存使用
-
Redis 有哪些类型
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)
| 类型 | 简介 | 特性 | 场景 |
|---|---|---|---|
| String(字符串) | 二进制安全 | 可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M | — |
| Hash(字典) | 键值对集合,即编程语言中的Map类型 | 适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去) | 存储、读取、修改用户属性 |
| List(列表) | 链表(双向链表) | 增删快,提供了操作某一段元素的API | 1,最新消息排行等功能(比如朋友圈的时间线) 2,消息队列 |
| Set(集合) | 哈希表实现,元素不重复 | 1、添加、删除,查找的复杂度都是O(1) 2、为集合提供了求交集、并集、差集等操作 | 1、共同好友 2、利用唯一性,统计访问网站的所有独立ip 3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐 |
| Sorted Set(有序集合) | 将Set中的元素增加一个权重参数score,元素按score有序排列 | 数据插入集合时,已经进行天然排序 | 1、排行榜 2、带权重的消息队列 |
-
Redis 内部结构
-
volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集中任意选择数据淘汰
allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
allkeys-random:从数据集中任意选择数据淘汰
no-enviction:当内存达到限制的时候,不淘汰任何数据,不可写入任何数据集,所有引起申请内存的命令会报错
-
聊聊 Redis 使用场景
-
Redis 持久化机制
RDB: 这是Redis默认的持久化方式,按照一定的时间周期策略把内存的数据以快照的形式保存到硬盘的二进制文件;
AOF: Redis会将每一个收到的写命令都通过Write函数追加到文件最后,类似于MySQL的binlog。当Redis重启是会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。
-
Redis 集群方案与实现
-
缓存崩溃
-
缓存降级
-
使用缓存的合理性问题
消息队列
- 消息队列的使用场景
- 消息的重发补偿解决思路
- 消息的堆积解决思路
- 自己如何实现消息队列
- 如何保证消息的有序性
- Kafka为什么快
- Kafka是如何实现几十万的高并发写入
框架篇
Spring
- BeanFactory 和 ApplicationContext 有什么区别
- Spring IOC 如何实现
- 说说 Spring AOP
- Spring AOP 实现原理
- 动态代理(cglib 与 JDK)
- Spring 事务实现方式
- Spring 事务底层原理
- Spring 其他产品(Srping Boot、Spring Cloud、Spring Secuirity、Spring Data、Spring AMQP 等)
Netty
- 为什么选择 Netty
- 说说业务中,Netty 的使用场景
- 原生的 NIO 在 JDK 1.7 版本存在 epoll bug
- 什么是TCP 粘包/拆包
- TCP粘包/拆包的解决办法
- Netty 线程模型
- 说说 Netty 的零拷贝
- Netty 内部执行流程
- Netty 重连实现
微服务篇
微服务
-
微服务哪些框架
-
如何解决跨域
-
你怎么理解 RPC 框架
-
说说 RPC 的实现原理
-
说说 Dubbo 的实现原理
-
你怎么理解 RESTful
-
如何理解 RESTful API 的幂等性
-
如何保证接口的幂等性
-
说说 CAP 定理、 BASE 理论

-
怎么考虑数据一致性问题
-
说说最终一致性的实现方案
-
微服务如何进行数据库管理
-
如何应对微服务的链式调用异常
-
对于快速追踪与定位问题
分布式
- 谈谈业务中使用分布式的场景
- Session 分布式方案
- 分布式锁的场景
- 分布是锁的实现方案
- 分布式事务
- 集群与负载均衡的算法与实现
- 说说分库与分表设计
- 分库与分表带来的分布式困境与应对之策
高级进阶
算法
排序算法
JVM
References JVM8中内存基本操作
性能优化
- 性能指标有哪些
- 如何发现性能瓶颈
- 性能调优的常见手段
- 说说你在项目中如何进行性能调优
面试官拷问
- 平时碰到系统CPU飙高和频繁GC,你会怎么排查?