关于java:大厂面试系列一些问题的答案

2次阅读

共计 15266 个字符,预计需要花费 39 分钟才能阅读完成。

知识点总结

  • InnoDB 的行锁

    (1)共享锁(S):用法 lock in share mode,又称读锁,容许一个事务去读一行,阻止其余事务取得雷同数据集的排他锁。若事务 T 对数据对象 A 加上 S 锁,则事务 T 能够读 A 但不能批改 A,其余事务只能再对 A 加 S 锁,而不能加 X 锁,直到 T 开释 A 上的 S 锁。这保障了其余事务能够读 A,但在 T 开释 A 上的 S 锁之前不能对 A 做任何批改。(2)排他锁(X):用法 for update,又称写锁,容许获取排他锁的事务更新数据,阻止其余事务获得雷同的数据集共享读锁和排他写锁。若事务 T 对数据对象 A 加上 X 锁,事务 T 能够读 A 也能够批改 A,其余事务不能再对 A 加任何锁,直到 T 开释 A 上的锁。在没有索引的状况下,InnoDB 只能应用表锁

  • Spring 的事务流传级别

    (1)REQUIRED(默认):反对应用以后事务,如果以后事务不存在,创立一个新事务。(2)SUPPORTS:反对应用以后事务,如果以后事务不存在,则不应用事务。(3)MANDATORY:强制,反对应用以后事务,如果以后事务不存在,则抛出 Exception。(4)REQUIRES_NEW:创立一个新事务,如果以后事务存在,把以后事务挂起。(5)NOT_SUPPORTED:无事务执行,如果以后事务存在,把以后事务挂起。(6)NEVER:无事务执行,如果以后有事务则抛出 Exception。(7)NESTED:嵌套事务,如果以后事务存在,那么在嵌套的事务中执行。如果以后事务不存在,则体现跟 REQUIRED 一样。

  • Redis 与 Mysql 双写一致性计划

先更新数据库,再删缓存。数据库的读操作的速度远快于写操作的,所以脏数据很难呈现。能够对异步延时删除策略,保障读申请实现当前,再进行删除操作

  • 索引 B + 树的叶子节点都能够存哪些货色?

可能存储的是整行数据,也有可能是主键的值。B+ 树的叶子节点存储了整行数据的是主键索引,也被称之为聚簇索引。而索引 B + Tree 的叶子节点存储了主键的值的是非主键索引,也被称之为非聚簇索引

  • 分代回收

(1)HotSpot JVM 把年老代分为了三局部:1 个 Eden 区和 2 个 Survivor 区(别离叫 from 和 to)。个别状况下,新创建的对象都会被调配到 Eden 区 (一些大对象非凡解决), 这些对象通过第一次 Minor GC 后,如果依然存活,将会被移到 Survivor 区。对象在 Survivor 区中每熬过一次 Minor GC,年龄就会减少 1 岁,当它的年龄减少到肯定水平时,就会被挪动到年轻代中。(2)因为年老代中的对象根本都是朝生夕死的,所以在年老代的垃圾回收算法应用的是复制算法,复制算法的根本思维就是将内存分为两块,每次只用其中一块,当这一块内存用完,就将还活着的对象复制到另外一块下面。复制算法不会产生内存碎片。(3)在 GC 开始的时候,对象只会存在于 Eden 区和名为“From”的 Survivor 区,Survivor 区“To”是空的。紧接着进行 GC,Eden 区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会依据他们的年龄值来决定去向。年龄达到肯定值(年龄阈值,能够通过 -XX:MaxTenuringThreshold 来设置) 的对象会被挪动到年轻代中,没有达到阈值的对象会被复制到“To”区域。通过这次 GC 后,Eden 区和 From 区曾经被清空。这个时候,“From”和“To”会替换他们的角色,也就是新的“To”就是上次 GC 前的“From”,新的“From”就是上次 GC 前的“To”。不管怎样,都会保障名为 To 的 Survivor 区域是空的。Minor GC 会始终反复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象挪动到年轻代中。

  • 线程之间如何通信?

(1)利用最根本的 synchronized(2)利用 synchronized、notify、wait(3)while 轮询的形式(4)利用 Lock 和 Condition(5)利用 volatile(6)利用 AtomicInteger(7)利用 CyclicBarrier(8)利用 PipedInputStream(9)利用 BlockingQueue

  • redis 并发竞争 key 的解决方案

(1)分布式锁 + 工夫戳(2)利用音讯队列

  • 如何防止(预防)死锁?

毁坏“申请和放弃”条件:让过程在申请资源时,一次性申请所有须要用到的资源,不要一次一次来申请,当申请的资源有一些没空,那就让线程期待。不过这个办法比拟浪费资源,过程可能常常处于饥饿状态。还有一种办法是,要求过程在申请资源前,要开释本人领有的资源。毁坏“不可抢占”条件:容许过程进行抢占,办法一:如果去抢资源,被回绝,就开释本人的资源。办法二:操作系统容许抢,只有你优先级大,能够抢到。毁坏“循环期待”条件:将零碎中的所有资源对立编号,过程可在任何时刻提出资源申请,但所有申请必须依照资源的编号程序提出(指定获取锁的程序,程序加锁)

  • 高并发零碎的设计与实现

在开发高并发零碎时有三把利器用来爱护零碎:缓存、降级和限流。(1)缓存:缓存比拟好了解,在大型高并发零碎中,如果没有缓存数据库将分分钟被爆,零碎也会霎时瘫痪。应用缓存不单单可能晋升零碎访问速度、进步并发访问量,也是爱护数据库、爱护零碎的无效形式。大型网站个别次要是“读”,缓存的应用很容易被想到。在大型“写”零碎中,缓存也经常扮演者十分重要的角色。比方累积一些数据批量写入,内存外面的缓存队列(生产生产),以及 HBase 写数据的机制等等也都是通过缓存晋升零碎的吞吐量或者实现零碎的保护措施。甚至消息中间件,你也能够认为是一种分布式的数据缓存。(2)降级:服务降级是当服务器压力剧增的状况下,依据以后业务状况及流量对一些服务和页面有策略的降级,以此开释服务器资源以保障外围工作的失常运行。降级往往会指定不同的级别,面临不同的异样等级执行不同的解决。依据服务形式:能够拒接服务,能够提早服务,也有时候能够随机服务。依据服务范畴:能够砍掉某个性能,也能够砍掉某些模块。总之服务降级须要依据不同的业务需要采纳不同的降级策略。次要的目标就是服务尽管有损然而总比没有好。(3)限流:限流能够认为服务降级的一种,限流就是限度零碎的输出和输入流量已达到爱护零碎的目标。一般来说零碎的吞吐量是能够被测算的,为了保证系统的稳固运行,一旦达到的须要限度的阈值,就须要限度流量并采取一些措施以实现限度流量的目标。比方:提早解决,回绝解决,或者局部回绝解决等等。

  • 高并发零碎的限流如何实现?

常见的限流算法有计数器、漏桶和令牌桶算法。漏桶算法在分布式环境中消息中间件或者 Redis 都是可选的计划。发放令牌的频率减少能够晋升整体数据处理的速度,而通过每次获取令牌的个数减少或者加快令牌的发放速度和升高整体数据处理速度。而漏桶不行,因为它的流出速率是固定的,程序处理速度也是固定的。

  • JVM 有哪些回收算法

    1)援用计数法(2)复制算法(3)标记 - 革除算法(4)标记 - 整顿算法(5)分代收集算法

  • 垃圾收集器有哪些?

(1)Serial 收集器(2)ParNew 收集器(3)Parallel Scavenge 收集器(4)Serial Old 收集器(5)Parallel Old 收集器(6)CMS 收集器(7)G1 收集器 (8)ZGC

  • 常见的分布式事务计划有哪些?

(1)两阶段提交计划(2)eBay 事件队列计划(3)TCC 弥补模式(4)缓存数据最终一致性

  • 运行时数据区域(内存模型)

(1)程序计数器:程序计数器是一块较小的内存空间,它能够看作是以后线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码解释器工作时就是通过扭转这个计数器的值来选取下一条须要执行的字节码指令,分支、循环、跳转、异样解决、线程复原等根底性能都须要依赖这个计数器来实现。是线程公有”的内存。(2)Java 虚拟机栈:与程序计数器一样,Java 虚拟机栈(Java Virtual Machine Stacks)也是线程公有的,它的生命周期与线程雷同。虚拟机栈形容的是 Java 办法执行的内存模型:每个办法在执行的同时都会创立一个栈帧,用于存储局部变量表、操作数栈、动静链接、办法进口等信息。每一个办法从调用直至执行实现的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。(3)本地办法栈:本地办法栈(Native Method Stack)与虚拟机栈所施展的作用是十分类似的,它们之间的区别不过是虚拟机栈为虚拟机执行 Java 办法(也就是字节码)服务,而本地办法栈则为虚拟机应用到的 Native 办法服务。(4)Java 堆:对于大多数利用来说,Java 堆是 Java 虚拟机所治理的内存中最大的一块。Java 堆是被所有线程共享的一块内存区域,在虚拟机启动时创立。此内存区域的惟一目标就是寄存对象实例,简直所有的对象实例都在这里分配内存。(5)办法区(1.8 叫元数据): 办法区与 Java 堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、动态变量、即时编译器编译后的代码等数据。

  • CAS 操作 ABA 问题

如果在这段期间它的值已经被改成了 B,起初又被改回为 A,那 CAS 操作就会误认为它素来没有被扭转过。Java 并发包为了解决这个问题,提供了一个带有标记的原子援用类“AtomicStampedReference”,它能够通过管制变量值的版本来保障 CAS 的正确性

  • 为什么抉择 B + 树作为索引构造?

(1)Hash 索引:Hash 索引底层是哈希表,哈希表是一种以 key-value 存储数据的构造,所以多个数据在存储关系上是齐全没有任何程序关系的,所以,对于区间查问是无奈间接通过索引查问的,就须要全表扫描。所以,哈希索引只实用于等值查问的场景。而 B + 树是一种多路均衡查问树,所以他的节点是人造有序的(左子节点小于父节点、父节点小于右子节点),所以对于范畴查问的时候不须要做全表扫描(2)二叉查找树:解决了排序的根本问题,然而因为无奈保障均衡,可能进化为链表。(3)均衡二叉树:通过旋转解决了均衡的问题,然而旋转操作效率太低。(4)红黑树:通过舍弃严格的均衡和引入红黑节点,解决了 AVL 旋转效率过低的问题,然而在磁盘等场景下,树依然太高,IO 次数太多。(5)B+ 树:在 B 树的根底上,将非叶节点革新为不存储数据纯索引节点,进一步升高了树的高度;此外将叶节点应用指针连接成链表,范畴查问更加高效。

  • 脏读和幻读是什么?

(1)脏读是指当一个事务正在拜访数据,并且对数据进行了批改。而这种批改还没有提交到数据库中,这时,另外一个事务也拜访了这个数据,而后应用了这个数据。(2)幻读是指当事务不是独立执行时产生的一种景象,例如第一个事务对一个表中的数据进行了批改,这种批改波及到了表中的全副数据行。同时,第二个事务也批改了这个表中的数据,这种批改是向表中插入一行新数据。那么,当前就会产生操作第一个事务的用户发现表中还有没有批改的数据行,就如同产生了幻觉一样。

  • 如何解决 Redis 缓存雪崩,缓存穿透问题?

缓存雪崩: (1)应用 Redis 高可用架构:应用 Redis 集群来保障 Redis 服务不会挂掉 (2)缓存工夫不统一,给缓存的生效工夫,加上一个随机值,防止个体生效 (3)限流降级策略:有肯定的备案,比方共性举荐服务不可用了,换成热点数据举荐服务 缓存穿透:(1)在接口做校验 (2)存 null 值(缓存击穿加锁)(3)布隆过滤器拦挡:将所有可能的查问 key 先映射到布隆过滤器中,查问时先判断 key 是否存在布隆过滤器中,存在才持续向下执行,如果不存在,则间接返回。布隆过滤器将值进行屡次哈希 bit 存储,布隆过滤器说某个元素在,可能会被误判。布隆过滤器说某个元素不在,那么肯定不在。

  • Redis 的长久化机制

redis 为了保障效率,数据缓存在了内存中,然而会周期性的把更新的数据写入磁盘或者把批改操作写入追加的记录文件中,以保证数据的长久化。Redis 的长久化策略有两种:(1)RDB:快照模式是间接把内存中的数据保留到一个 dump 的文件中,定时保留,保留策略。当 Redis 须要做长久化时,Redis 会 fork 一个子过程,子过程将数据写到磁盘上一个长期 RDB 文件中。当子过程实现写临时文件后,将原来的 RDB 替换掉。(2)AOF:把所有的对 Redis 的服务器进行批改的命令都存到一个文件里,命令的汇合。应用 AOF 做长久化,每一个写命令都通过 write 函数追加到 appendonly.aof 中。aof 的默认策略是每秒钟 fsync 一次,在这种配置下,就算产生故障停机,也最多失落一秒钟的数据。毛病是对于雷同的数据集来说,AOF 的文件体积通常要大于 RDB 文件的体积。依据所应用的 fsync 策略,AOF 的速度可能会慢于 RDB。Redis 默认是快照 RDB 的长久化形式。

  • 三次握手

(1)第一次握手:建设连贯时,客户端发送 syn 包(syn=x)到服务器,并进入 SYN_SENT 状态,期待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。(2)第二次握手:服务器收到 syn 包,必须确认客户的 SYN(ack=x+1),同时本人也发送一个 SYN 包(syn=y),即 SYN+ACK 包,此时服务器进入 SYN_RECV 状态;(3)第三次握手:客户端收到服务器的 SYN+ACK 包,向服务器发送确认包 ACK(ack=y+1),此包发送结束,客户端和服务器进入 ESTABLISHED(TCP 连贯胜利)状态,实现三次握手。

  • Kafka 音讯是采纳 Pull 模式,还是 Push 模式?

Kafka 最后思考的问题是,customer 应该从 brokes 拉取音讯还是 brokers 将音讯推送到 consumer,也就是 pull 还 push。在这方面,Kafka 遵循了一种大部分音讯零碎独特的传统的设计:producer 将音讯推送到 broker,consumer 从 broker 拉取音讯。push 模式下,当 broker 推送的速率远大于 consumer 生产的速率时,consumer 恐怕就要解体了。最终 Kafka 还是选取了传统的 pull 模式。Pull 模式的另外一个益处是 consumer 能够自主决定是否批量的从 broker 拉取数据。Pull 有个毛病是,如果 broker 没有可供生产的音讯,将导致 consumer 一直在循环中轮询,直到新音讯达到。为了防止这点,Kafka 有个参数能够让 consumer 阻塞晓得新音讯达到。

  • HashMap 相干

(1)在 jdk1.8 之后,HashMap 除了数组 + 链表之外,援用了红黑树。须要阐明对于援用了红黑树的 HashMap 如何 put 一个元素,以及链表是在何时转化为红黑树的。比方,首先须要晓得这个元素落在哪一个数组里,获取 hashcode 后并不是对数组长度取余来确定的,而是高下位异或求与来失去的。这个中央首先得晓得异或求与是做什么样的运算的。(2)之后说一下在 HashMap 中的实现,比方 hashcode 无符号右移 16 位后和原 hashcode 做异或运算,这相当于把 hashcode 的高 16 位拿过去和 hashcode 的低 16 位做异或运算,因为无符号右移后后面说的 16 位都补零,这就是后面说的 “ 高下位异或“,进而是“求与”,和谁求与呢,和数组长度减 1 求与。说到这里起码可能证实你是看过源码的,接下来说说你的思考,比方咱们晓得对于 hashmap 初始化容量决定了数组大小,个别咱们对于数组这个初始容量的设置是有法则的,它应该是 2^n。这个初始容量的设置影响了 HashMap 的效率,那又波及到影响 HashMap 效率的次要因素,比方初始容量和负载因子。

  • 手写一个基于懒汉式的双重检测的单例。

(1)单例有三个比拟要害的点,一是公有构造方法,防止内部 new 出对象;二是保障唯一性;三是提供一个全局拜访点。(2)另外,懒汉式双重检测的实现形式 有三点须要留神的中央,一是全局拜访点必须是动态的,外界应用能够通过类间接调用,二是在进入锁之后还须要校验,三是保留单例对象的公有变量肯定要用 volatile 润饰,这个中央能够多说一些,比方 volatile 避免指令重排序,保障内存可见性(JVM 层面和 CPU 层面能够别离说)。

  • RPC 原理

(1)为什么会呈现 RPC?RPC(Remote Procedure Call Protocol)——近程过程调用协定。一般来说,本人写程序而后本地调用,这种程序的特点是服务的生产方和提供方。当咱们进入公司时,面对的很可能就是成千上万的服务提供方,这时候就须要应用 RPC 来进行近程服务调用。RPC 将原来的本地调用转变为调用远端的服务器上的办法,给零碎的解决能力和吞吐量带来了近似于无限度晋升的可能。(2)RPC 的组成 ①客户端:服务的调用方 ②客户端存根:寄存服务端的地址音讯,再将客户端的申请参数打包成网络音讯,③而后通过网络近程发送给服务方。④服务端:真正的服务提供者。⑤服务端存根:接管客户端发送过去的音讯,将音讯解包,并调用本地的办法。

  • Redis 缓存回收机制

(1)数据过期:①定时删除策略:Redis 启动一个定时器监控所有的 key, 一旦有过期的话就进行删除(遍历所有 key, 十分消耗 CPU)②惰性删除策略:获取 key 的时候判断是否过期,过期则进行删除 Redis 采纳的形式:①(随机抓取一部分 key 进行检测)+②(2)内存淘汰:①noeviction:当内存不足以包容新写入数据时,新写入操作会报错。(Redis 默认策略)②allkeys-lru:当内存不足以包容新写入数据时,在键空间中,移除最近起码应用的 Key。(LRU 举荐应用)③allkeys-random:当内存不足以包容新写入数据时,在键空间中,随机移除某个 Key。④volatile-lru:当内存不足以包容新写入数据时,在设置了过期工夫的键空间中,移除最近起码应用的 Key。这种状况个别是把 Redis 既当缓存,又做长久化存储的时候才用。⑤volatile-random:当内存不足以包容新写入数据时,在设置了过期工夫的键空间中,随机移除某个 Key。⑥volatile-ttl:当内存不足以包容新写入数据时,在设置了过期工夫的键空间中,有更早过期工夫的 Key 优先移除。不举荐。如果没有对应的键,则回退到 noeviction 策略。

  • Redis 主从同步

(1)主从复制作用 ①数据冗余 ②故障复原(服务冗余)③负载平衡 ④读写拆散(主节点写操作、从节点读操作)(2)主从复制过程 ①连贯建设阶段 步骤 1:保留主节点信息 步骤 2:建设 socket 连贯 步骤 3:发送 ping 命令 步骤 4:身份验证 步骤 5:发送从节点端口信息 ②数据同步阶段 从节点向主节点发送 psync 命令 依据主从节点以后状态的不同,能够分为全量复制和局部复制 ③命令流传阶段 主从节点进入命令流传阶段;在这个阶段主节点将本人执行的写命令发送给从节点,从节点接管命令并执行,从而保障主从节点数据的一致性。(3)介绍全量复制和局部复制 ①全量复制:用于首次复制或其余无奈进行局部复制的状况,将主节点中的所有数据都发送给从节点,是一个十分重型的操作。②局部复制:用于网络中断等状况后的复制,只将中断期间主节点执行的写命令发送给从节点,与全量复制相比更加高效。须要留神的是,如果网络中断工夫过长,导致主节点没有可能残缺地保留中断期间执行的写命令,则无奈进行局部复制,仍应用全量复制。(4)主从复制毛病:故障复原无奈自动化;写操作无奈负载平衡;存储能力受到单机的限度。

  • 为什么会有哨兵机制?

在主从复制的根底上,哨兵实现了自动化的故障复原。

  • 哨兵机制作用?

(1)监控(Monitoring):哨兵会一直地查看主节点和从节点是否运作失常。(2)主动故障转移(Automatic failover):当主节点不能失常工作时,哨兵会开始主动故障转移操作,它会将生效主节点的其中一个从节点降级为新的主节点,并让其余从节点改为复制新的主节点。(3)配置提供者(Configuration provider):客户端在初始化时,通过连贯哨兵来取得以后 Redis 服务的主节点地址。(4)告诉(Notification):哨兵能够将故障转移的后果发送给客户端。

  • 哨兵机制节点组成?

它由两局部组成,哨兵节点和数据节点:(1)哨兵节点:哨兵零碎由一个或多个哨兵节点组成,哨兵节点是非凡的 redis 节点,不存储数据。(2)数据节点:主节点和从节点都是数据节点。

  • 哨兵机制原理?

(1)定时工作:每个哨兵节点保护了 3 个定时工作。定时工作的性能别离如下:通过向主从节点发送 info 命令获取最新的主从构造;通过公布订阅性能获取其余哨兵节点的信息;通过向其余节点发送 ping 命令进行心跳检测,判断是否下线。(2)主观下线:在心跳检测的定时工作中,如果其余节点超过肯定工夫没有回复,哨兵节点就会将其进行主观下线。顾名思义,主观下线的意思是一个哨兵节点“主观地”判断下线;与主观下线绝对应的是主观下线。(3)主观下线:哨兵节点在对主节点进行主观下线后,会通过 sentinel is-master-down-by-addr 命令询问其余哨兵节点该主节点的状态;如果判断主节点下线的哨兵数量达到肯定数值,则对该主节点进行主观下线。(4)选举领导者哨兵节点:当主节点被判断主观下线当前,各个哨兵节点会进行协商,选举出一个领导者哨兵节点,并由该领导者节点对其进行故障转移操作。监督该主节点的所有哨兵都有可能被选为领导者,选举应用的算法是 Raft 算法;Raft 算法的基本思路是先到先得:即在一轮选举中,哨兵 A 向 B 发送成为领导者的申请,如果 B 没有批准过其余哨兵,则会批准 A 成为领导者。选举的具体过程这里不做详细描述,一般来说,哨兵抉择的过程很快,谁先实现主观下线,个别就能成为领导者。(5)故障转移:选举出的领导者哨兵,开始进行故障转移操作,该操作大体能够分为 3 个步骤:①在从节点中抉择新的主节点:抉择的准则是,首先过滤掉不衰弱的从节点;而后抉择优先级最高的从节点 (由 slave-priority 指定);如果优先级无奈辨别,则抉择复制偏移量最大的从节点;如果仍无奈辨别,则抉择 runid 最小的从节点。②更新主从状态:通过 slaveof no one 命令,让选出来的从节点成为主节点;并通过 slaveof 命令让其余节点成为其从节点。③将曾经下线的主节点(即 6379) 设置为新的主节点的从节点,当 6379 从新上线后,它会成为新的主节点的从节点。

  • 哨兵机制毛病

写操作无奈负载平衡;存储能力受到单机的限度。(Redis 集群解决了该状况)

  • Zookeeper 锁是如何实现的?

个别应用 Curator 进行应用 Zookeeper 锁,例如有两个客户端 A 和客户端 B, 首先 A 先在锁节点下创立例如 01 子节点的锁,而后再获取节点信息,发现自己的 01 节点排名第一,那么就取得锁。客户端 B 也须要获取锁,当初锁节点下创立例如 02 的子节点,而后再获取锁节点信息,发现锁节点信息为[01,02], 并不排第一,因而获取不到锁,客户端 B 会在他的程序节点的上一个程序节点加一个监听器。当客户端 A 应用完锁,删除 01 节点,客户端 B 获取到 01 删除的监听,而后发现自己的 02 节点排名第一,那么就获取到锁。

  • JVM 内存模型

(1)程序计数器:线程公有,用来程序跳转,流程管制(2)办法区(1.8 叫元数据区):线程共享,用于存储类信息、常量、动态变量等信息(3)Java 虚拟机栈:线程公有,用于办法调用 Java 虚拟机栈会呈现两种谬误:StackOverFlowError 和 OutOfMemoryError(4)堆:线程公有,次要的内存区域,存储对象实例,垃圾回收次要针对这一块。(5)本地办法栈:线程共享,本地办法被执行的时候,在本地办法栈也会创立一个栈帧,用于寄存该本地办法的局部变量表、操作数栈、动静链接、进口信息。

  • G1 和 CMS 垃圾回收器

G1 和 CMS 垃圾回收器(1)CMS 收集器:是一种以获取最短回收进展工夫为指标的收集器。过程:①初始标记:标记 GC Roots 能间接关联到的对象,须要在 safepoint 地位暂停所有执行线程。—->STW ②并发标记:进行 GC Roots Tracing,遍历完从 root 可达的所有对象。该阶段与工作线程并发执行。③从新标记:修改并发标记期间因用户程序持续运作而导致标记产生表动的那一部分对象的标记记录。须要在 safepoint 地位暂停所有执行线程。—>STW ④并发革除:开启用户线程,同时 GC 线程开始对为标记的区域做打扫。长处:并发收集、低进展。毛病:①CMS 收集器对 CPU 资源十分敏感。②CMS 收集器无奈解决浮动垃圾(Floating Garbage)。③CMS 收集器是基于标记 - 革除算法,该算法毛病都有:标记和革除效率低 / 产生大量不间断的内存碎片。④进展工夫是不可预期的。(2)G1 收集器:从新定义了堆空间,突破了原有的分代模型,将堆划分为一个个区域。这么做的目标是在进行收集时不用在全堆范畴内进行,这是它最显著的特点。过程:①初始标记:标记 GC Roots 能够间接关联的对象,该阶段须要线程进展然而耗时短。—->STW ②并发标记:寻找存活的对象,能够与其余程序并发执行,耗时较长。③最终标记:并发标记期间用户程序会导致标记记录产生变动(好比一个阿姨一边清理垃圾,另一个人一边扔垃圾)虚构机会将这段时间的变动记录在 Remembered Set Logs 中。最终标记阶段会向 Remembered Set 合并并发标记阶段的变动。这个阶段须要线程进展,也能够并发执行 —->STW ④筛选回收:对每个 Region 的回收老本进行排序,依照用户自定义的回收工夫来制订回收打算 长处:①空间整合:G1 应用 Region 独立区域概念,G1 利用的是标记复制法,不会产生垃圾碎片 ②分代收集:G1 能够本人治理新生代和老年代 ③并行于并发:G1 能够通过机器的多核来并发解决 STW 进展,缩小进展工夫,并且可不进展 java 线程执行 GC 动作,可通过并发形式让 GC 和 java 程序同时执行。④可预测进展:G1 除了谋求进展工夫,还建设了可预测进展工夫模型,能让制订的 M 毫秒工夫片段内,耗费在垃圾回收器上的工夫不超过 N 毫秒 毛病:G1 须要记忆集 (具体来说是卡表)来记录新生代和老年代之间的援用关系,这种数据结构在 G1 中须要占用大量的内存,可能达到整个堆内存容量的 20% 甚至更多。而且 G1 中保护记忆集的老本较高,带来了更高的执行负载,影响效率。

  • wait/await 和 sleep 区别

(1)两者最次要的区别在于:sleep 办法没有开释锁,而 wait 办法开释了锁。(2)两者都能够暂停线程的执行。(3)wait 通常被用于线程间交互 / 通信,sleep 通常被用于暂停执行。(4)wait() 办法被调用后,线程不会主动昏迷,须要别的线程调用同一个对象上的 notify() 或者 notifyAll() 办法。sleep() 办法执行实现后,线程会主动昏迷。或者能够应用 wait(long timeout)超时后线程会主动昏迷。

  • Redis 的 LRU 过期策略的具体实现 Redis 的 LRU 具体实现

用栈的模式会导致执行 select * 的时候大量非热点数据霸占头部数据,所以须要改良。Redis 每次按 key 获取一个值的时候,都会更新 value 中的 lru 字段为以后秒级别的工夫戳。Redis 初始的实现算法很简略,随机从 dict 中取出五个 key, 淘汰一个 lru 字段值最小的。在 3.0 的时候,又改良了一版算法,首先第一次随机选取的 key 都会放入一个 pool 中(pool 的大小为 16),pool 中的 key 是按 lru 大小顺序排列的。接下来每次随机选取的 keylru 值必须小于 pool 中最小的 lru 才会持续放入,直到将 pool 放满。放满之后,每次如果有新的 key 须要放入,须要将 pool 中 lru 最大的一个 key 取出。淘汰的时候,间接从 pool 中选取一个 lru 最小的值而后将其淘汰。

  • 哪些对象能够作为 GC Roots?

(1)虚拟机栈(栈帧中的本地变量表)中援用的对象。(2)办法区中类动态属性援用的对象。(3)办法区中常量援用的对象。(4)本地办法栈中 JNI(即个别说的 Native 办法)援用的对象。

  • ConcurrentHashMap 的数据结构

在 JDK1.7 版本中,ConcurrentHashMap 保护了一个 Segment 数组,Segment 这个类继承了重入锁 ReentrantLock,并且该类外面保护了一个 HashEntry<K,V>[] table 数组,在写操作 put,remove,扩容的时候,会对 Segment 加锁,所以仅仅影响这个 Segment,不同的 Segment 还是能够并发的,所以解决了线程的平安问题,同时又采纳了分段锁也晋升了并发的效率。在 JDK1.8 版本中,ConcurrentHashMap 摒弃了 Segment 的概念,而是间接用 Node 数组 + 链表 + 红黑树的数据结构来实现,并发管制应用 Synchronized 和 CAS 来操作,整个看起来就像是优化过且线程平安的 HashMap。

  • tcp 和 udp 的长处与毛病

(1)TCP 的长处:牢靠,稳固 TCP 的牢靠体现在 TCP 在传递数据之前,会有三次握手来建设连贯,而且在数据传递时,有确认、窗口、重传、拥塞管制机制,在数据传完后,还会断开连接用来节约系统资源。(2)TCP 的毛病:慢,效率低,占用系统资源高,易被攻打 TCP 在传递数据之前,要先建连贯,这会耗费工夫,而且在数据传递时,确认机制、重传机制、拥塞管制机制等都会耗费大量的工夫,而且要在每台设施上保护所有的传输连贯,事实上,每个连贯都会占用零碎的 CPU、内存等硬件资源。而且,因为 TCP 有确认机制、三次握手机制,这些也导致 TCP 容易被人利用,实现 DOS、DDOS、CC 等攻打。(3)UDP 的长处:快,比 TCP 稍平安 UDP 没有 TCP 的握手、确认、窗口、重传、拥塞管制等机制,UDP 是一个无状态的传输协定,所以它在传递数据时十分快。没有 TCP 的这些机制,UDP 较 TCP 被攻击者利用的破绽就要少一些。但 UDP 也是无奈防止攻打的,比方:UDP Flood 攻打……(4)UDP 的毛病:不牢靠,不稳固 因为 UDP 没有 TCP 那些牢靠的机制,在数据传递时,如果网络品质不好,就会很容易丢包。基于下面的优缺点,那么:什么时候应该应用 TCP:当对网络通讯品质有要求的时候,比方:整个数据要准确无误的传递给对方,这往往用于一些要求牢靠的利用,比方 HTTP、HTTPS、FTP 等传输文件的协定,POP、SMTP 等邮件传输的协定。在日常生活中,常见应用 TCP 协定的利用如下:浏览器,用的 HTTP FlashFXP,用的 FTP Outlook,用的 POP、SMTP Putty,用的 Telnet、SSH QQ 文件传输。什么时候应该应用 UDP:当对网络通讯品质要求不高的时候,要求网络通讯速度能尽量的快,这时就能够应用 UDP。比方,日常生活中,常见应用 UDP 协定的利用如下:QQ 语音 QQ 视频 TFTP。

  • HashMap 原理

(1)hashMap 是非线程平安的,hashMap 1.7 的底层实现为数组(table[])+链表(LinkList–>Entry),hashmap 1.8 底层为数组 + 链表 / 红黑树(当链表长度达到阈值 TREEIFY_THRESHOLD(默认为 8)时,会转化为红黑树)

  • HashMap 的 put 和 resize 的过程

(1)put 过程:①查看数组是否须要初始化 ②依据 key 计算 hashcode ③依据 hashcode 计算出桶地位 ④遍历链表,查看 key 值与链表节点的 key 值是否相等,如果相等的话,那么进行笼罩旧值,并返回旧值。1.8 的话须要先查看链表长度是否达到阈值,如果达到阈值,先进行红黑树转化而后再进行查看扩容。⑤新增的时候须要查看是否须要扩容,须要扩容的话进行两倍扩容,扩容实现后进行插入新值。(2)resize 过程:resize 扩容须要从四个方面来进行答复:①什么时候触发 resize? 当容量超过以后容量(默认容量 16)乘以负载因子(默认 0.75)就会进行扩容,扩容大小为以后大小的两倍(扩大问题,为啥是两倍:通过限度 length 是一个 2 的幂数,h & (length-1)和 h % length 后果是统一的)。②resize 是如何 hash 的:h & (length-1) ③resize 是如何进行链表操作的:应用头插法进行数据插入,每次新 put 的值放在头部 ④并发操作下,链表是如何成环的:HashMap 的环:若以后线程此时取得 ertry 节点,然而被线程中断无奈继续执行,此时线程二进入 transfer 函数,并把函数顺利执行,此时新表中的某个地位有了节点,之后线程一取得执行权继续执行,因为并发 transfer,所以两者都是扩容的同一个链表,当线程一执行到 e.next = new table[i] 的时候,因为线程二之前数据迁徙的起因导致此时 new table[i] 上就有 ertry 存在,所以线程一执行的时候,会将 next 节点,设置为本人,导致本人相互应用 next 援用对方,因而产生链表,导致死循环。

  • 线程池有哪些类型

①FixedThreadPool: 创立可重用固定线程数的线程池。②SingleThreadPool: 创立只有一个线程的线程池。③CachedThreadPool: 一个可依据须要创立新线程的线程池,如果现有线程没有可用的,则创立一个新线程并增加到池中,如果有被应用完然而还没销毁的线程,就复用该线程。终止并从缓存中移除那些已有 60 秒钟未被应用的线程。因而,长时间放弃闲暇的线程池不会应用任何资源。④ScheduledThreadPool:创立一个线程池,它可安顿在给定提早后运行命令或者定期地执行。

  • ConcurrentHashMap 分段锁原理

(1)ConcurrentHashMap 采纳了分段锁技术,其中 Segement 继承了 RecentLock,当 ConcurrentHashMap 进行 get、put 操作时,均是同步的。各个 Segement 之间的 get、put 操作能够进行并发,即当一个线程拜访 ConcurrentHashMap 的 Segement 时,不会影响对其余 Segement 的拜访。

  • B- 树和 B + 树区别

1)B- 树和 B 树是一个概念,是多路搜寻树(相比于二叉搜寻树,IO 次数更少)。B- 树的个性:①关键字汇合散布在整颗树中;②任何一个关键字呈现且只呈现在一个结点中;③搜寻有可能在非叶子结点完结;④其搜寻性能等价于在关键字选集内做一次二分查找;⑤其最底搜寻性能为 O(logN)(2)B+ 树是 B - 树的变体,也是一种多路搜寻树 B+ 的个性:①所有关键字都呈现在叶子结点的链表中(浓密索引),且链表中的关键字恰好是有序的;②不可能在非叶子结点命中;③非叶子结点相当于是叶子结点的索引(稠密索引),叶子结点相当于是存储(关键字)数据的数据层;④更适宜文件索引零碎;(3)B+ 树的劣势:①繁多节点存储更多的元素,使得查问的 IO 次数更少。②所有查问都要查找到叶子节点,查问性能稳固。③所有叶子节点造成有序链表,便于范畴查问。

  • Mysql 数据库索引原理

(1)MyISAM 索引实现:MyISAM 引擎应用 B +Tree 作为索引构造,叶节点的 data 域寄存的是数据记录的地址。(2)Innodb 索引实现:①第一个重大区别是 InnoDB 的数据文件自身就是索引文件。MyISAM 索引文件和数据文件是拆散的,索引文件仅保留数据记录的地址。而在 InnoDB 中,表数据文件自身就是按 B +Tree 组织的一个索引构造,这棵树的叶节点 data 域保留了残缺的数据记录。这个索引的 key 是数据表的主键,因而 InnoDB 表数据文件自身就是主索引。②第二个与 MyISAM 索引的不同是 InnoDB 的辅助索引 data 域存储相应记录主键的值而不是地址。换句话说,InnoDB 的所有辅助索引都援用主键作为 data 域。

  • 组合索引怎么应用?最左匹配的原理。

1)组合索引怎么应用?例如组合索引(a,b,c),组合索引的失效准则是:从前往后顺次应用失效,如果两头某个索引没有应用,那么断点后面(范畴值也算断点,orderby 不算断点,用到索引)的索引局部起作用,断点前面的索引没有起作用;(2)最左匹配的原理:以最右边的为终点任何间断的索引都能匹配上

  • Spring 生命周期

Bean 的生命周期概括起来就是 4 个阶段:(1)实例化(Instantiation)(2)属性赋值(Populate)(3)初始化(Initialization)(4)销毁(Destruction)

  • Spring 几种 scope 区别?

(1)singleton:Spring 的 IOC 容器中只有一个实例 bean,该值为 scope 的默认值(2)prototype:每次 getBean 时都会创立一个新的实例(3)request: 每次申请都会创立一个实体 bean(4)session:每次 session 申请时都会创立一个实体 bean(5)globalsession: 每个全局的 HTTP Session,应用 session 定义的 Bean 都将产生一个新实例。

  • Spring AOP 实现有哪几种实现

接口代理和类代理会有什么区别?(1)Spring AOP 有两种实现,均为动静代理:①JDK 动静代理:基于反射进行动静代理,外围类是 InvocationHandker 类和 Proxy 类,被代理的类必须实现接口 ②CGLIB 动静代理:被代理类无需实现接口,次要实现 MethodInterceptor 接口即可实现代理(2)Spring AOP 如果代理的类存在接口,优先应用 JDK 动静代理,否则应用 CGLIB 动静代理。
欢送搜寻关注自己与敌人共同开发的微信面经小程序【大厂面试助手】和公众号【微瞰技术】

正文完
 0