1、分布锁的实现方式
参考:分布式锁的三种实现方式
2、什么时候使用volatile
参考:Java 面试宝典:volatile 的使用场景有哪些?
3、Hashmap和ConcurrentHashMap底层实现原理
1. HashMap
HashMap 是 Java 中的一个非同步的散列映射表,它使用一个数组来存储键值对,并且通过计算键的哈希码来确定每个键值对在数组中的位置。
底层实现原理:
数组: HashMap 内部使用一个长度为 n 的数组来保存键值对,其中 n 是数组的容量(capacity)。
哈希函数: 对于每个键(key),HashMap 会调用其 hashCode() 方法,然后使用这个哈希码通过某种哈希算法(例如取模运算)来计算数组中的索引。
链表/红黑树: 如果两个键通过哈希函数得到的索引相同,这两个键值对会被存储在同一个数组槽位上。为了解决这个问题,HashMap 使用链表(或在 Java 8 之后,当链表长度超过一定阈值时,转换为红黑树)来解决冲突。
扩容机制:
当 HashMap 中的元素数量超过其容量(即数组长度)的负载因子(默认是0.75)时,它会自动扩容,通常是原来的两倍。
扩容时会重新计算每个元素的哈希码并重新放置到新的数组位置上。
2. ConcurrentHashMap
ConcurrentHashMap 是 Java 中的一个线程安全的散列映射表,它允许多个线程同时进行读写操作而不会引起数据不一致的问题。
底层实现原理:
分段锁(Segment): 在 Java 8 之前,ConcurrentHashMap 使用分段锁(Segment)的概念来实现线程安全。每个 Segment 都是一个小的 HashMap,并且可以被不同的线程独立地锁定。
CAS操作和synchronized: 在 Java 8 之后,ConcurrentHashMap 使用了一种更高效的方式:基于节点的无锁并发控制算法(如 CAS)和一些细粒度的锁(如 synchronized 或 Lock)。
Node节点: ConcurrentHashMap 中的每个元素都是一个 Node 对象,它包含了键、值、指向下一个节点的引用等信息。
扩容机制: 当元素数量达到扩容阈值时,ConcurrentHashMap 会进行扩容。扩容时,它会创建一个新的更大的数组,并使用一个线程来协助迁移旧数组中的元素到新数组中。
主要改进点:
减少锁的粒度:在 Java 8 中,通过将整个桶数组分割成多个小的桶(称为“段”或“桶”),每个桶可以独立地进行锁定和解锁操作,从而减少了锁的竞争。
使用CAS操作:在 Java 8 中,对于大多数操作(如插入、删除、查找),使用了 CAS 操作来避免使用锁,从而提高并发性能。
链表到红黑树的转换:当链表长度超过一定阈值时,会将链表转换为红黑树以提高搜索效率。
总结
HashMap 使用数组和链表(或红黑树)来解决哈希冲突,并通过扩容机制来处理容量不足的情况。
ConcurrentHashMap 在 Java 8 之前使用分段锁来实现线程安全;在 Java 8 中则通过节点级别的 CAS 操作和锁的精细控制来实现更高的并发性能。两者都通过哈希函数和适当的结构来解决哈希冲突。
4、如何解决缓存穿透和缓存雪崩
参考:Redis详解(十二)------ 缓存穿透、缓存击穿、缓存雪崩
5、垃圾回收机制
参考:【Java虚拟机】JVM垃圾回收机制和常见回收算法原理
6、kafka选型依据
7、MySQL中有哪些锁类型
1. 全局锁:
读锁(共享锁):阻止其他用户更新数据,但允许读取数据。常用于需要确保数据一致性的操作,如全库备份。可以通过FLUSH TABLES WITH READ LOCK(FTWRL)语句添加全局读锁,使用UNLOCK TABLES语句释放锁定12。
写锁(排他锁):阻止其他用户读取和更新数据。常用于大量数据修改操作,确保数据不被干扰12。
2. 表级锁:
表锁:针对整张表进行加锁,适用于需要操作整张表的情况,如DDL操作或备份。表锁开销小、加锁快,但并发度低,容易出现锁冲突23。
3. 行级锁:
行锁:针对数据表中的某一行进行加锁,减少锁冲突,提高并发性和系统吞吐量。InnoDB引擎支持行锁23。
间隙锁(Gap Lock):锁定一个范围,防止幻读。常用于外键约束和重复读操作4。
临键锁(Next-Key Lock):结合行锁和间隙锁,防止幻读和重复读4。
4. 页面锁:
针对数据页进行加锁,适用于大批量数据的处理4。
5. 乐观锁与悲观锁:
乐观锁:假设冲突发生的概率较低,通过版本号或时间戳来控制并发访问。适用于写操作不频繁的场景4
8、mysql 间隙锁和邻键锁区别以及适用场景
在MySQL中,锁的类型对于并发控制和数据一致性至关重要。间隙锁(Gap Locks)和邻键锁(Next-Key Locks)是InnoDB存储引擎用来处理行级锁的两种方式,特别是在执行范围查询时。这两种锁的设计主要是为了解决幻读(Phantom Reads)的问题。
间隙锁(Gap Locks)
间隙锁锁定的是一个范围,而不是具体的行。当一个事务对某个范围的数据加锁时,它阻止其他事务在这个范围内插入新的行。间隙锁主要用于防止幻读。例如,如果你有一个范围查询锁定了一个区间内的所有行,间隙锁会阻止在该区间内插入新行。
适用场景:
防止插入操作:当你需要确保在一定范围内没有新的行被插入时。
优化并发性能:在高并发环境下,通过锁定不需要的间隙可以减少锁的竞争。
邻键锁(Next-Key Locks)
邻键锁是间隙锁和行锁的结合。它不仅锁定一个范围(间隙),还包括这个范围内的所有行。这确保了既防止了在该范围内插入新行,也防止了其他事务修改或删除范围内的行。邻键锁用于实现可重复读(REPEATABLE READ)隔离级别,这是InnoDB的默认隔离级别。
适用场景:
可重复读隔离级别:在默认的隔离级别下,邻键锁用于确保事务在读取数据时,数据不会被其他事务修改。
防止幻读:在执行范围查询时,通过锁定查询涉及的所有行和间隙,防止其他事务插入新行到查询范围内,从而实现防止幻读。
区别
范围:间隙锁锁定的是两个行之间的空间(间隙),而邻键锁锁定的是具体的行以及该行之前的间隙。
目的:间隙锁主要用于防止新的插入操作,而邻键锁用于防止新的插入和修改/删除操作,同时防止幻读。
隔离级别:在可重复读隔离级别下,InnoDB使用邻键锁;而在读已提交(READ COMMITTED)隔离级别下,通常只使用行锁,不会使用间隙锁或邻键锁来防止幻读。
总结
使用间隙锁来防止在特定范围内插入新行。
使用邻键锁来实现可重复读隔离级别,防止幻读,包括锁定范围内的所有行和间隙。
选择使用哪种类型的锁取决于你的具体需求和隔离级别设置。在大多数情况下,尤其是在默认的隔离级别下,你不需要手动管理这些锁的类型;InnoDB会自动为你处理这些细节。然而,了解它们的区别和适用场景可以帮助你更好地理解事务的行为和性能调优。
参考:【MySQL】一文带你理清<行级锁>(行锁,间隙锁,临键锁
MySQL锁、加锁机制(超详细)—— 锁分类、全局锁、共享锁、排他锁;表锁、元数据锁、意向锁;行锁、间隙锁、临键锁;乐观锁、悲观锁
9、springboot 慢接口如何排查
10、抽奖活动的高可用、高并发优化
JAVA巧用Redis中的原子性操作,解决秒杀并发中的问题,如商品一卖二
11、阿里云服务器 如何处理网站高并发流量问题?
12、三高问题
13、高并发下扣减库存
14、jemalloc分配机制的介绍及其优化实践
15、接口优化关注点
16、大数据常见面试
大数据常见面试题及答案(Linux、Zookeeper、Hadoop、Hive)
17、多个事务并发插入数据违反唯一性约束会导致死锁
18、阿里巴巴、亚马逊、谷歌、京东等大公司是如何设计高并发秒杀系统
19、MQ集群崩溃时如何保证秒杀系统高可用
20、分布式服务强一致性算法
22、kafka Rebalance协议
kafka知识点--offset管理和Consumer Rebalance
Kafka Consumer 消费消息和 Rebalance 机制
23、分布式事务
24、分库分表
25、分布式事务框架seata
微服务分布式事务之LCN、TCC特点、事务补偿机制缘由以及设计重点
26、Redis拆分
27、kafka事务消息
Kafka Exactly Once 语义实现原理:幂等性与事务消息