面试题

/ 默认分类 / 0 条评论 / 192浏览

一、mysql (innodb)2大知识点

1.1 索引结构 (b+树)

1.2 事务 (ACID)如 隔离级别、mvcc、死锁

二、redis

2.1 常用的数据类型(type) 如 string、hash、list..

2.2 redis的使用 比如 mysql和reids的数据一致;缓存雪崩、缓存击穿等;各类型使用场景

2.3 redis过期删除的方法(定期、惰性)

2.4 redis淘汰策略(指内存不够时的处理)(lru、ttl、random)

2.5 redis底层数据结构(即编码方式encoding)如zset 使用ziplist(压缩表)和skiplist(跳跃表)数据量小的时候使用ziplist超过128个则使用skiplist

2.6 redis的单线程的问题

三、java基础

3.1 HashMap 和 ConcurrentHashMap

3.2 锁 如 synchronized、AQS、cas、分布式锁

3.3 线程池 核心参数和基本流程

3.4 Thread 的使用

3.5 ThreadLocal

3.6 并发包下的类的使用 如CountDownLatch、AtomicInteger

java内存模型 JMM定义了Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式。JVM是整个计算机虚拟模型,所以JMM是隶属于JVM的。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存、写缓冲区、寄存器以及其他的硬件和编译器优化。

ReentrantLock Java 中的线程池 volatile 请谈谈 ThreadLocal 是怎么解决并发安全的?

hashCode & equals 1、如果两个对象相同,那么它们的hashCode值一定要相同; 2、如果两个对象的hashCode相同,它们并不一定相同 上面说的对象相同指的是用eqauls方法比较。 你当然可以不按要求去做了,但你会发现,相同的对象可以出现在Set集合中。同时,增加新元素的效率会大大下降

HashMap hash 方法”扰动函数“

ConcurrentHashMap 采用了分段锁技术,其中 Segment 继承于 ReentrantLock。不会像 HashTable 那样不管是 put 还是 get 操作都需要做同步处理,理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发。每当一个线程占用锁访问一个 Segment 时,不会影响到其他的 Segment。

cas + synchronized

请 谈 谈 ThreadLocal 是 怎 么 解 决 并 发 安 全 的 ? ThreadLocal 这 是 Java 提 供 的 一 种 保 存 线 程 私 有 信 息 的 机 制 , 因 为 其 在 整 个 线 程 生 命 周 期 内 有 效 , 所 以 可 以 方 便 地 在 一 个 线 程 关 联 的 不 同 业 务 模 块 之 间 传 递 信 息 , 比 如 事 务 ID、 Cookie 等 上 下 文 相 关 信 息 。ThreadLocal 为 每 一 个 线 程 维 护 变 量 的 副 本 , 把 共 享 数 据 的 可 见 范 围 限 制 在 同 一 个 线 程 之 内 , 其 实 现 原 理 是 , 在 ThreadLocal 类 中 有 一 个 Map, 用 于 存 储 每 一 个 线 程 的 变 量 的 副 本

InnoDB 行锁实现方式: InnoDB 行锁是通过给索引上的索引项加锁来实现的,这一点 MySQL 与 Oracle 不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB 这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB 才使用行级锁,否则,InnoDB 将使用表锁! 不论是使用主键索引、唯一索引或普通索引,InnoDB 都会使用行锁来对数据加锁。 只有执行计划真正使用了索引,才能使用行锁:即便在条件中使用了索引字段,但是否使用索引来检索数据是由 MySQL 通过判断不同执行计划的代价来决定的,如果 MySQL 认为全表扫描效率更高,比如对一些很小的表,它就不会使用索引,这种情况下 InnoDB 将使用表锁,而不是行锁。因此,在分析锁冲突时, 别忘了检查 SQL 的执行计划(可以通过 explain 检查 SQL 的执行计划),以确认是否真正使用了索引。(更多阅读:MySQL索引总结) 由于 MySQL 的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然多个session是访问不同行的记录, 但是如果是使用相同的索引键, 是会出现锁冲突的(后使用这些索引的session需要等待先使用索引的session释放锁后,才能获取锁)。 应用设计的时候要注意这一点。

GAP锁为了防止幻读

mysql ACID 原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)

undo log 回滚日志 redo log 重做日志

分布式系统 cap原理 一致性 、 可用性 、 分区容错性

eureka优先保证可用性 ap zk 进行leader选举 保证cp

线程池 任务进来时,首先执行判断,判断核心线程是否处于空闲状态,如果不是,核心线程就先就执行任务,如果核心线程已满,则判断任务队列是否有地方存放该任务,若果有,就将任务保存在任务队列中,等待执行,如果满了,在判断最大可容纳的线程数,如果没有超出这个数量,就开创非核心线程执行任务,如果超出了,就调用handler实现拒绝策略 有四种:第一种AbortPolicy:不执行新任务,直接抛出异常,提示线程池已满

         第二种DisCardPolicy:不执行新任务,也不抛出异常

         第三种DisCardOldSetPolicy:将消息队列中的第一个任务替换为当前新进来的任务执行

         第四种CallerRunsPolicy:直接调用execute来执行当前任务

CachedThreadPool:可缓存的线程池,该线程池中没有核心线程,非核心线程的数量为Integer.max_value,就是无限大,当有需要时创建线程来执行任务,没有需要时回收线程,适用于耗时少,任务量大的情况。

SecudleThreadPool:周期性执行任务的线程池,按照某种特定的计划执行线程中的任务,有核心线程,但也有非核心线程,非核心线程的大小也为无限大。适用于执行周期性的任务。

SingleThreadPool:只有一条线程来执行任务,适用于有顺序的任务的应用场景。

FixedThreadPool:定长的线程池,有核心线程,核心线程的即为最大的线程数量,没有非核心线程

ScheduledExecutorService scheduleWithFixedDelay scheduleAtFixedRate

ElasticSearch推荐的最大JVM堆空间是30~32G, 所以把你的分片最大容量限制为30GB, 然后再对分片数量做合理估算. 例如, 你认为你的数据能达到200GB, 我们推荐你最多分配7到8个分片.

G1 核心参数 可选项及默认值 描述 -XX:+UseG1GC 采用 Garbage First (G1) 收集器 -XX:MaxGCPauseMillis=n 设置最大GC 暂停时间。这是一个大概值,JVM 会尽可能的满足此值 -XX:InitiatingHeapOccupancyPercent=n 设置触发标记周期的 Java 堆占用率阈值。默认占用率是整个 Java 堆的 45%。默认值 45. -XX:NewRatio=n new/old 年代的大小比例. 默认值 2. -XX:SurvivorRatio=n eden/survivor 空间的大小比例. 默认值 8. -XX:MaxTenuringThreshold=n 对象晋升年代的最大阀值。默认值 15.这个参数需要注意的是:最大值是15,不要超过这个数啊,要不然会被人笑话。原因为:JVM内部使用 4 bit (1111)来表示这个数。 -XX:ParallelGCThreads=n 设置在垃圾回收器的并行阶段使用的线程数。默认值因与 JVM 运行的平台而不同。 -XX:ConcGCThreads=n 并发垃圾收集器使用的线程数。默认值因与 JVM 运行的平台而不同。 -XX:G1HeapRegionSize=n 使用G1,Java堆被划分为大小均匀的区域。这个参数配置各个子区域的大小。此参数的默认值根据堆大小的人工进行确定。最小值为 1Mb 且最大值为 32Mb。

ThreadLocal ThreadLocal的作用:实现线程范围内的局部变量,即ThreadLocal在一个线程中是共享的,在不同线程之间是隔离的。

ThreadLocal的原理:ThreadLocal存入值时使用当前ThreadLocal实例作为key,存入当前线程对象中的Map中去。最开始在看源码之前,我以为是以当前线程对象作为key将对象存入到ThreadLocal中的Map中去

threadLocal内存泄漏 由于threadLocalMap的生命周期跟thread一样长,如果没有手动删除对应key就会导致内存泄漏 threadLocal正确使用方法 1、每次使用完都调用remove()方法 2、将threadLocal变量定义为private static 这样就一直存在threadLocal的强引用,也就能保证任何时候都能通过threadLocal的弱引用访问到Entry的value值,进而清除掉

接口和抽象类 接口:对类的行为进行约束 like a的关系 抽象类:代码复用 is a的关系 使用场景:当你关注一个事务的本质的时候抽象类,关注一个操作的时候,用接口

缓存雪崩:缓存同一时间大面积失效 随机失效时间、锁 缓存穿透:缓存和数据库都没有数据 校验、nullAble 缓存击穿:缓存没有数据库有同一条数据 缓存永不过期、锁

缓存和数据库一致性 先更新数据库、再删除缓存(缓存删除失败的情况)

事务的ACID 原子性、一致性、隔离性、持久性 隔离性4个级别:读未提交 脏读、读已提交 2次读取结果不一致,不可重复读、可重复读 (MVCC)、串行化

GC如何判断对象是否可以回收 引用计数器 可达性分析法 从GC ROOTS开始向下搜索

并发特性 原子性、可见性、有序性

公平锁和非公平锁 区别在加锁阶段 加锁时,公平锁会先看AQS队列是否在排队,非公平锁会直接竞争锁 当锁释放是都是先唤醒最前面的线程

sychronized锁升级 偏向锁 轻量级锁 通过自旋来实现 重量级锁 会导致线程阻塞

服务熔断、服务降级 熔断是下游触发的、降级是为了降低系统负载

微服务优点 1、独立项目,独立部署 耦合性降低 2、技术灵活 3、性能提高 缺点:服务调用的复杂性提高、分布式事务、测试难度

进程和线程的关系 进程是资源分配的最小单位,线程是CPU调度的最小单位

四、Redis为什么这么快 1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);

2、数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;

3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;

4、使用多路I/O复用模型,非阻塞IO;

5、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

以上几点都比较好理解,下边我们针对多路 I/O 复用模型进行简单的探讨:

(1)多路 I/O 复用模型

多路I/O复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。

**这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。**采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响Redis性能的瓶颈,主要由以上几点造就了 Redis 具有很高的吞吐量。 这里我们一直在强调的单线程,只是在处理我们的网络请求的时候只有一个线程来处理

mysql b 与 b+的区别 B-树有如下特点: 所有键值分布在整颗树中(索引值和具体data都在每个节点里); 任何一个关键字出现且只出现在一个结点中; 搜索有可能在非叶子结点结束(最好情况O(1)就能找到数据); 在关键字全集内做一次查找,性能逼近二分查找; B+树是B-树的变体,也是一种多路搜索树, 它与 B- 树的不同之处在于: 所有关键字存储在叶子节点出现,内部节点(非叶子节点并不存储真正的 data) 为所有叶子结点增加了一个链指针

JAVA 内存屏障 对Load Barrier来说,在读指令前插入读屏障,可以让高速缓存中的数据失效,重新从主内存加载数据 对Store Barrier来说,在写指令之后插入写屏障,能让写入缓存的最新数据写回到主内存

a. 通过 Synchronized关键字包住的代码区域,当线程进入到该区域读取变量信息时,保证读到的是最新的值.这是因为在同步区内对变量的写入操作,在离开同步区时就将当前线程内的数据刷新到内存中,而对数据的读取也不能从缓存读取,只能从内存中读取,保证了数据的读有效性.这就是插入了StoreStore屏障 b. 使用了volatile修饰变量,则对变量的写操作,会插入StoreLoad屏障. c. 其余的操作,则需要通过Unsafe这个类来执行. UNSAFE.putOrderedObject类似这样的方法,会插入StoreStore内存屏障 Unsafe.putVolatiObject 则是插入了StoreLoad屏障

redis 类型及编码格式 字符串类型的内部编码: int 8个字节的长整型 embstr: 小于等于39个字节的字符串 raw: 大于39个字节的字符串 redis会根据当前值的类型长度去判断选用那种内部编码实现;

哈希类型的内部编码: ziplist(压缩列表): 当哈希元素个数小于hash-max-ziplist-entries配置(默认512个),同时所有值都小于hash-max-ziplist-value配置(默认64字节),redis会使用ziplist作为哈希的内部实现,ziplist使用更加紧凑的结构实现多个元素的连续存储,所以在节省内存方面比hashtable更加优秀 hashtable(哈希表): 当哈希类型无法满足ziplist的条件时, redis会使用hashtable作为哈希的内部实现,因为此时ziplist的读写效率会下降,而hashtable的读写时间复杂度为O(1); 列表类型的内部编码: ziplist(压缩列表): 当列表元素个数小于list-max-ziplist-entries配置(默认512个),同时所有值都小于list-max-ziplist-value配置(默认64字节),redis会使用ziplist作为列表的内部实现来减少内存的使用 linkedlist(链表): 当列表类型无法满足ziplist的条件的时候.redis会采用linkedlist作为链表的内部实现; quicklist : 在redis3.2 版本后,一种新的数据结构,结合了ziplist和quicklist的优点,所以采用redis3.2以后版本的列表的内部编码都采用了quicklist; 集合类型的内部编码: intset(整数集合): 当集合元素个数小于set-max-ziplist-entries配置(默认512个),redis会使用intset作为集合的内部实现来减少内存的使用 hashtable(哈希表): 当集合类型无法满足intset的条件时,redis会使用hashtable作为集合的内部实现 有序集合类型的内部编码: ziplist(压缩列表): 当列表元素个数小于zset-max-ziplist-entries配置(默认128个),同时所有值都小于zset-max-ziplist-value配置(默认64字节),redis会使用ziplist作为列表的内部实现来减少内存的使用 skiplist(跳跃表): 当ziplist条件不满足时,有序集合会使用skiplist作为内部实现,因为此时ziplist的读写效率会下降

redis淘汰策略 1、volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰 2、volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰 3、volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰 4、allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰 5、allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰 6、no-enviction(驱逐):禁止驱逐数据

redis持久化方案

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储。 AOF持久化以日志的形式记录服务器所处理的每一个写、删除操作,查询操作不会记录,以文本的方式记录,可以打开文件看到详细的操作记录。

es倒排索引 Elasticsearch 使用一种称为倒排索引的结构,它适用于快速的全文搜索。一个倒排索引由文档中所有不重复词的列表构成,对于其中每个词,有一个包含它的文档列表。 es使用称为倒排索引的结构达到快速全文搜索的目的。 一个倒排索引包含一系列不同的单词,这些单词出现在任何一个文档, 对于每个单词,对应着所有它出现的文档。 倒排索引建立的是分词(Term)和文档(Document)之间的映射关系,在倒排索引中,数据是面向词(Term)而不是面向文档的

Hi,小伙伴 如果你想 记录美好 ?