B 站面试
-
Java 根底
-
ArrayList 与 LinkedList 的区别?
- ArrayList 是基于动静数组实现,LinedList 是基于链表构造实现的
- 对于随机的拜访 ArrayList 要优先于 Linkedist,linkedList 须要挪动指针
- 对于插入、删除数据 LinkedList 只须要扭转前后的指针援用即可,ArrayList 须要挪动插入 / 删除的元素 比拟耗时
-
-
AQS 简述其中一些罕用的技术(ReentrantLock)
-
AQS(AbstracyQueueSynchronizer)形象队列同步器
state(int) Queue(null)次要实现的原理波及的 2 个参数
-
-
引申:Synchronized 与 ReentrantLock 的区别?
- Synchronized 锁的转换, 偏差锁(无锁 -> 偏差锁 -> 轻量级锁 -> 重量级锁)?
-
Synchronized 是 Java 关键字, 是 JVM 层面的锁, 在代码块 / 办法中通过 notify/wait 来实现,ReentrantLock 是 jdk 原生的锁, 底层原理是 CAS
- 是否能够手动开释:Synchronized 不能够手动开释锁, 必须代码块 / 办法执行实现后才能够开释锁,ReentrantLock 如果遗记了开释锁就会始终持有锁导致死锁, 所以个别将开释锁的操作放在 finally 中执行开释 unlock()操作。
- 是否能够中断:Synchronized 是不可中断的锁, 必须是线程执行实现 / 代码中出现异常。ReentrantLock 是能够中断的,tryLock(timeout,TimeUnit)设置超时办法或者将 lockInterruptibly()放到代码块中,调用 interrupt 办法进行中断
- 是否偏心:synchronized 为非偏心锁 ReentrantLock 则即能够选偏心锁也能够选非偏心锁,通过构造方法 new ReentrantLock 时传入 boolean 值进行抉择,为空默认 false 非偏心锁,true 为偏心锁
- 锁的唤醒的准确:synchronized 不能绑定;ReentrantLock 通过绑定 Condition 联合 await()/singal()办法实现线程的准确唤醒,而不是像 synchronized 通过 Object 类的 wait()/notify()/notifyAll()办法要么随机唤醒一个线程要么唤醒全副线程。
- 锁的对象:synchronzied 锁的是对象,锁是保留在对象头外面的,依据对象头数据来标识是否有线程取得锁 / 争抢锁;ReentrantLock 锁的是线程,依据进入的线程和 int 类型的 state 标识锁的取得 / 争抢
-
多线程的应用形式?(线程池应用及一些外围参数简介及线程数如何设置)
-
多线程个别应用 ThreadPoolExecutor 来创立自定义线程池, 线程池参数
- coreSize: 外围线程数
- maxSize: 最大线程数
- time: 外围线程存活的最长工夫
- timeUnit: 存活的工夫单位
- queue: 存储新来的工作的队列
- abortPolicy: 回绝策略
- factory: 创立线程的自定义工厂
-
线程数的创立个别是依据业务的性质决定线程数的配置, 个别是 CPU 密集型 /IO 密集型
个别是依据这个公式进行计算: 线程数 =[(线程等待时间 + 线程解决工夫)/ 线程解决工夫]Ncpu 数,CPU 密集型线程的 IO 耗时根本为 0, 也就是计算的后果就是 Ncpu 数,IO 密集型线程期待阻塞工夫是线程解决工夫的倍数, 假如等待时间与解决工夫相等那个就是 2 Ncpu 数
-
-
Spring 中罕用的设计模式简介?(代理模式、工厂模式、单例模式)
- 代理模式:AOP 切面(JDK 动静代理模式 &CGlib 代理模式)
- 工厂模式:FactoryBean(定义一个创立工厂的接口, 对象的创立实例化交由工厂来实现)
- 单例模式: 保障实例化的 bean 只有一个, 能够通过 singleton=“true|false”或者 scope=“?”来指定
- 观察者模式: 一种一对多的依赖关系,当一个对象的状态产生扭转时,所有依赖于它的对象都失去告诉并被自动更新,spring 中 Observer 模式罕用的中央是 listener 的实现。如 ApplicationListener
- 策略模式: 定义一系列的算法,把它们一个个封装起来,并且使它们可互相替换。本模式使得算法可独立于应用它的客户而变动
-
volatile 和 final 关键字
- volatile
-
final(能够润饰类、办法、变量)
- final 润饰类: 那么这个类是不能被继承的, 这个类中的所有的办法隐式的会变成 final
- final 润饰办法: 那么该办法不能被子类重写, 须要留神的一点是:因为重写的前提是子类能够从父类中继承此办法,如果父类中 final 润饰的办法同时访问控制权限为 private,将会导致子类中不能间接继承到此办法,因而,此时能够在子类中定义雷同的办法名和参数,此时不再产生重写与 final 的矛盾,而是在子类中从新定义了新的办法。(注:类的 private 办法会隐式地被指定为 final 办法。
-
final 润饰变量: 只能被赋值一次, 赋值后不再扭转, 当 final 润饰一个根本数据类型时,示意该根本数据类型的值一旦在初始化后便不能发生变化;
- 如果 final 润饰一个援用类型时,则在对其初始化之后便不能再让其指向其余对象了,但该援用所指向的对象的内容是能够发生变化的。实质上是一回事,因为援用的值是一个地址,final 要求值,即地址的值不发生变化。
- final 润饰一个成员变量(属性),必须要显示初始化。这里有两种初始化形式,一种是在变量申明的时候初始化;第二种办法是在申明变量的时候不赋初值,然而要在这个变量所在的类的所有的构造函数中对这个变量赋初值。
- 当函数的参数类型申明为 final 时,阐明该参数是只读型的。即你能够读取应用该参数,然而无奈扭转该参数的值
-
ThreadLocal 的应用, 以及应用的留神点?为什么会内存透露?
- ThreadLocal 是多线程状况下避免对同一变量进行操作, 每个线程有本人的本地变量进行操作, 不相互影响.
- ThreadLocal 的存储形式相似 Map 构造 key 和 value, 存储 set, 取值 get, 删除 remove,key 为以后线程的援用
- ThreadLocal 的 key 是软援用, 因为 ThreadLcoal 的存储构造是 Entry, 而 Entry 继承了 WeakReference<ThreadLocal<?>>, 当存储数据的时候 new 进去的实例 Entry, 存储的 key 就是弱援用, 这样会导致一个内存溢出的问题, 当内存不足的时候 JVM 会进行 GC,GC 会将软援用进行回收, 那么 key 被回收了,value 会始终存在, 这会使得内存一直的扩充但又无奈进行回收。所以 在应用 ThreadLocal 的时候应用实现后肯定要在 finally 块中进行 remove
-
Java 中对象的援用分为哪几类?
- 强援用(StrongReference)
最强悍的个别都是 new 进去的实例对象 - 软援用 (SoftReference)
它的作用是通知垃圾回收器,程序中的哪些对象是不那么重要,当内存不足的时候是能够被临时回收的。当 JVM 中的内存不足的时候,垃圾回收器会开释那些只被软援用所指向的对象。如果全副开释完这些对象之后,内存还有余,才会抛出 OutOfMemory 谬误。软援用非常适合于创立缓存。当零碎内存不足的时候,缓存中的内容是能够被开释的 - 弱援用 (WeakReferene)
它的作用是援用一个对象,然而并不阻止该对象被回收。如果应用一个强援用的话,只有该援用存在,那么被援用的对象是不能被回收的。弱援用则没有这个问题。在垃圾回收器运行的时候,如果一个对象的所有援用都是弱援用的话,该对象会被回收。弱援用的作用在于解决强援用所带来的对象之间在存活工夫上的耦合关系。弱援用最常见的用途是在汇合类中,尤其在哈希表中。哈希表的接口容许应用任何 Java 对象作为键来应用。当一个键值对被放入到哈希表中之后,哈希表对象自身就有了对这些键和值对象的援用。如果这种援用是强援用的话,那么只有哈希表对象自身还存活,其中所蕴含的键和值对象是不会被回收的。如果某个存活工夫很长的哈希表中蕴含的键值对很多,最终就有可能消耗掉 JVM 中全副的内存 - 虚援用 (PhantomReference)
在 Object 类外面有个 finalize 办法,其设计的初衷是在一个对象被真正回收之前,能够用来执行一些清理的工作。因为 Java 并没有提供相似 C ++ 的析构函数一样的机制,就通过 finalize 办法来实现。然而问题在于垃圾回收器的运行工夫是不固定的,所以这些清理工作的理论运行工夫也是不能预知的。幽灵援用(phantom reference)能够解决这个问题。在创立幽灵援用 PhantomReference 的时候必须要指定一个援用队列。当一个对象的 finalize 办法曾经被调用了之后,这个对象的幽灵援用会被退出到队列中。通过查看该队列外面的内容就晓得一个对象是不是曾经筹备要被回收了.
程序能够通过判断援用队列中是否曾经退出了虚援用,来理解被援用的对象是否将要被垃圾回收。如果程序发现某个虚援用曾经被退出到援用队列,那么就能够在所援用的对象的内存被回收之前采取必要的口头.
- 强援用(StrongReference)
- ConcurrentHashMap 与 Map 的区别以及 ConcurrentHashMap 的实现原理?
- 多路复用 IO 的原理?
-
中间件
-
redis 的根本数据结构?
- String、Set、Sorted Set、Map、List
-
redis 根本数据类型联合具体的场景?
- 实现购物车用什么数据结构类型? — Map
- 实现随机取出 3 个获奖名单?– set, 应用 set 的 pop 弹出命令
- 实现排名的前 3 名?– Sorted Set 的 ZRang 命令排序取前 3 个数值
- 取一个人的独特好友?— Set, 应用 set 的 union 命令
-
redis 为什么很快?
- 单线程, 无需线程的上下文切换
- 内存操作
- 多路复用 IO 模型
-
-
redis 实现分布式锁?
- redis 实现分布式锁形式是 setnx 命令, 也就是多线程在并发的时候对同一个 key 进行设置数值, 其余的线程在进行抢占锁的时候会发现这个 key 曾经存在数值, 那么就会放弃这个抢占锁的操作
-
redis 的分布式锁的实现会遇到很多坑:
- A 线程在 setnx 之后始终解决业务不开释锁, 就会导致其余的线程始终期待 无奈拿到锁, 这样线程池就会被打满, 所以线程在设置锁时候须要增加锁的超时工夫, 当锁的执行超过了工夫就会被动开释锁
-
A 线程在执行过程中在规定的超时工夫内实现业务解决并发送了开释了锁的 del 命令, 然而因为零碎负荷 / 网络起因导致命令没有发送胜利, 到了超时工夫, 被动开释了锁, 那么 B 线程拿到了锁,B 线程在处理过程中进行, 此时 A 的命令重试胜利删除了锁, 那么 B 这个会有不可预计的谬误. 所以咱们在 del 的时候要先拿到这个 key 对应的 value,value 的值不要惟一这样会呈现误删除锁的状况, 并且 get 和 del 的操作要保障原子性(Lua 脚本来编写,lua 脚本只是一行操作命令开始和完结两头无论多少操作, 都是一次性执行)
- zookeeper 与 eureka 的区别?应用注册核心的优缺点?
- 两个都是先实现服务注册的中间件
- CAP 实践:C: 一致性 A: 可用性 P: 分区容错性
-
zookeeper 只能保障 CAP 实践中的 CP, 一致性其实并不一定是强一致性而是最终一致性,P 分区容错型也就是就集群的高可用, 这个是分布式系统的根底, 因为 zk 的选举机制会导致 zk 的集群的不可用, 当 zk 的主挂了之后进行选举的时候 整个集群是不可用的这个在分布式系统是致命的, 能够容忍数据的不统一然而不可用这个无论那个零碎业务都无奈接受的(当 master 节点因为网络故障与其余节点失去分割时,残余节点会从新进行 leader 选举。问题在于,选举 leader 的工夫太长,30 ~ 120s, 且选举期间整个 zk 集群都是不可用的,这就导致在选举期间注册服务瘫痪)。
- eureka 保障了 CAP 中的 AP:P 就不说了这是根底,C 也不是强一致性保障最终一致性即可,A: 可用性,Eureka 还有一种自我爱护机制,如果在 15 分钟内超过 85% 的节点都没有失常的心跳,那么 Eureka 就认为客户端与注册核心呈现了网络故障:1.Eureka 不再从注册列表中移除因为长时间没收到心跳而应该过期的服务 2.Eureka 依然可能承受新服务的注册和查问申请,然而不会被同步到其它节点上(即保障以后节点仍然可用)3. 当网络稳固时,以后实例新的注册信息会被同步到其它节点中(Eureka 领有客户端缓存技术:Eureka 分为客户端程序与服务器端程序两个局部,客户端程序负责向外提供注册与发现服务接口)。所以即使 Eureka 集群中所有节点都生效,或者产生网络宰割故障导致客户端不能拜访任何一台 Eureka 服务器;Eureka 服务的消费者依然能够通过 Eureka 客户端缓存来获取现有的服务注册信息。甚至最极其的环境下,所有失常的 Eureka 节点都不对申请产生相应,也没有更好的服务器解决方案来解 决这种问题时;得益于 Eureka 的客户端缓存技术,消费者服务依然能够通过 Eureka 客户端查问与获取注册服务信息)
- zookeeper 来实现分布式锁?
- 首先 zk 有 4 个节点类型: 长久节点、长久程序节点、长期节点、长期程序节点
-
zk 实现分布式锁的节点就是利用了长期程序节点的个性, 实现 zk 的分布式锁一个长久节点作为 root 节点, 在该节点下新建长期程序节点, 比方 Client- A 在 /root/lock1 节点,CLient- B 在目录下新建 /root/lock2 节点, 所有的节点都是程序递增的, 那么客户端在获取锁的时候判断本人的节点是否是以后节点汇合中的最小节点, 是就获取到锁, 不是就在以后节点的上个节点增加 watcher 来监听 lock1 节点是否存在,CLient- C 则监听 lock2, 记得不是监听第一个节点, 如果监听第一个节点, 当节点删除后, 所有的长期节点都会收到这个音讯, 多个节点又同时去争抢这个锁(羊群效用), 当变动产生时,ZooKeeper 会触发一个特定的 znode 节点的变动导致的所有监督点的汇合。如果有 1000 个客户端通过 exists 操作监督这个 znode 节点,那么当 znode 节点创立后就会发送 1000 个告诉,因此被监督的 znode 节点的一个变动会产生一个尖峰的告诉,该尖峰可能带来影响,例如,在尖峰时刻提交的操作提早。可能的话,咱们倡议在应用 ZooKeeper 时,防止在一个特定节点设置大量的监督点,最好是每次在特定的 znode 节点上,只有大量的客户端设置监督点,现实状况下最多只设置一个.
- 音讯的反复生产如何解决?音讯来实现分布式事务?
-
数据库
-
Mysql 应用的引擎是什么?有什么区别?
- InnerDB/MySlamDB
- MySlam: 不反对事务也不反对外键,不反对行级锁,只反对并发插入的表锁,MyISAM 也是应用 B +tree 索引然而和 Innodb 的在具体实现上有些不同(优缺点:MyISAM 的劣势在于占用空间小,处理速度快。毛病是不反对事务的完整性和并发性)
- InnerDB 反对事务, 提供自增长列, 反对外键指出 MVCC 行级锁反对的索引类型是 B + 树(InnoDB 的劣势在于提供了良好的事务处理、解体修复能力和并发管制。毛病是读写效率较差,占用的数据空间绝对较大)
-
Mysql 中的索引的数据结构是什么?B+ 树与 Hash 索引的区别?
- InnerDB 应用的是 B + 数构造
-
Mysql 索引生效以及最左匹配准则?
- mysql 查问优化器会判断纠正这条 sql 语句该以什么样的程序执行效率最高,最初才生成真正的执行打算。所以,当然是咱们能尽量的利用到索引时的查问程序效率最高咯,所以 mysql 查问优化器会最终以这种程序进行查问执行。
- explain select * from test where b<10 and c <10;
explain select * from test where a<10 and c <10;
为什么 b<10 and c <10, 没有用到索引?而 a<10 and c <10 用到了?
当 b + 树的数据项是复合的数据结构,比方 (name,age,sex) 的时候,b+ 数是依照从左到右的程序来建设搜寻树的,比方当 (a,b,c) 这样的数据来检索的时候,b+ 树会优先比拟 name 来确定下一步的所搜方向,如果 name 雷同再顺次比拟 age 和 sex,最初失去检索的数据;但当 (b,c) 这样的没有 name 的数据来的时候,b+ 树就不晓得下一步该查哪个节点,因为建设搜寻树的时候 name 就是第一个比拟因子,必须要先依据 name 来搜寻能力晓得下一步去哪里查问。比方当 (a,c) 这样的数据来检索时,b+ 树能够用 name 来指定搜寻方向,但下一个字段 age 的缺失,所以只能把名字等于张三的数据都找到,而后再匹配性别是 F 的数据了,这个是十分重要的性质,即索引的最左匹配个性.
-
引申想到 ACID 的实现原理? 数据库的隔离级别?数据库的乐观锁?
-
ACID:
- A(原子性): 一个事务中多个操作要么都胜利要么都失败
- C(一致性): 在一个事务执行的前后,必须保障从一个统一状态变成另一个统一状态,举个例子:A 和 B 两者的钱一共 400 元,A 和 B 来回转账,不管转几次,怎么转最终后果都是 A 和 B 总计 400 元
- I(隔离性): 一个事务的操作与其余事务的操作是互不影响互相隔离的
- D(持久性): 对一个事务进行提交,如果提交胜利,那么数据肯定永恒保留下来,即使系统故障了,复原当前数据应该仍在。
-
隔离级别
- 读未提交: 啥玩意不是
- 读已提交: 可防止脏读
- 可反复读: 可防止脏读,不可反复读, 这是 Mysql 默认的隔离级别
- 序列化: 可防止脏读,不可反复读,幻读
- oracle 只有读已提交 (默认) 和串型化 2 种隔离级别
- 脏读:指当一个事务正在拜访数据,并且对数据进行了批改,而这种数据还没有提交到数据库中,这时,另外一个事务也拜访这个数据,而后应用了这个数据。因为这个数据还没有提交那么另外一个事务读取到的这个数据咱们称之为脏数据。根据脏数据所做的操作肯能是不正确的。
- 不可反复读:指在一个事务内,屡次读同一数据。在这个事务还没有执行完结,另外一个事务也拜访该同一数据,那么在第一个事务中的两次读取数据之间,因为第二个事务的批改第一个事务两次读到的数据可能是不一样的,这样就产生了在一个事物内两次间断读到的数据是不一样的,这种状况被称为是不可反复读。
- 幻象读:一个事务先后读取一个范畴的记录,但两次读取的纪录数不同,咱们称之为幻象读(两次执行同一条 select 语句会呈现不同的后果,第二次读会减少一数据行,并没有说这两次执行是在同一个事务中
-
-
-
数据结构
- 红黑数与均衡二叉树的区别?
- 红黑树的最长门路与最短门路的关系?
- 引申 –Map 的数据结构的变动由之前的链表构造 –> 红黑树的转换?