6-1 HashMap和CurrentHashMap的区别是什么?
HashMap 和 ConcurrentHashMap 是 Java 中常用的两种 Map 实现类,两者的不同点在于
1.HashMap 是非线程安全的,不适合在多线程环境下进行并发操作。
ConcurrentHashMap Java 1.7 使用了锁分段技术,Java 1.8 中,引入了 CAS 操作和 Synchronized 实现的,这种方式在高并发情况下性能更好,减少了锁的竞争。,是线程安全的。
2.在单线程环境下,HashMap 的性能可能会略优于 ConcurrentHashMap,因为 ConcurrentHashMap 需要额外的开销来维护并发访问的一致性。
在多线程环境下,ConcurrentHashMap 的性能通常会优于手动对 HashMap 进行同步操作的方式。
3.HashMap 在迭代过程中,如果其他线程修改了 HashMap 的结构,会抛出异常。
ConcurrentHashMap 的迭代器是弱一致性的,允许在迭代期间对 Map 进行修改,但无法保证迭代器能够反映出最新的修改。
4.在创建时,ConcurrentHashMap 需要指定初始容量和负载因子,而 HashMap 可以选择不指定,使用默认值。
补充 Hashtable 较早实现也是线程安全
CurrentHashMap底层结构在1.7和1.8有什么不同?
在 Java 1.7 和 1.8 中,ConcurrentHashMap 的底层结构有一些重要的变化。
Java 1.7 中的 ConcurrentHashMap 使用了分段锁(Segmented Locking)的机制,将整个数据结构分成多个段(Segment),每个段拥有自己的锁。这样可以在多线程并发访问时,只锁定某个段,而不是整个数据结构,从而提高并发性能。但在高并发情况下,由于每个段的锁会相互竞争,可能会出现性能瓶颈。
Java 1.8 中对 ConcurrentHashMap 进行了重大改进,引入了 CAS 操作(Compare and Swap)和 Synchronized 实现的新机制。在 Java 1.8 中,ConcurrentHashMap 放弃了分段锁的机制,而是使用了一种全新的基于 CAS 操作和 Synchronized 实现的方式来保证并发安全。这种方式在高并发情况下性能更好,减少了锁的竞争。
因此,从 Java 1.8 开始,ConcurrentHashMap 的底层结构发生了重大变化,采用了更加高效的并发控制机制,提高了在高并发环境下的性能表现。
6-2 假设你有一批历史积分数据要存储,数量在kw条左右 存入mysql 你的方案是什么
对于数据库的海量数据存储,方案有很多,常见的有:分区,分表,集群,分库,对于历史积分存储的话我的方案会用到分表
1.对历史积分数据要存储,我们可以按历史时间拆分为多张表,例如每一个时间节点(月,年)为一张新表,要查询对应的数据只需要去对应的时间去查询即可
2.历史积分所用到的字段应该不会很多,但是数据量巨大我会采用水平分表的方法去处理,可以解决单表字段过多和数据过多的问题
6-3 请你说一说你的排行榜功能是如何实现的
在我们的项目中是采用积分数量来确定排名名次的,排名分为历史排名和实时排名,简单来说,要想形成排行榜,我们在查询数据库时,需要先对用户分组,再对积分求和,最终按照积分和排序
1.次查询排行榜时,在内存中对这么多数据做分组、求和、排序,对内存和CPU的占用会非常恐怖,不太靠谱。
我们的使用Redis来保存榜单数据了
2.历史榜单是曾经的某个月最后一天的排名结果,积分和排名已经确定,没有实时更新排序的需求
我们可以在每个月第一天的凌晨,使用定时任务,将上个月最终的排行榜数据写入到数据库,然后就可以清空redis中上个月的积分和榜单数据了
3.实时积分榜:只需要在我们原来保存积分的功能上改进一下,将积分保存到MySQL的同时保存到redis中进行榜单排序即可
6-4 历史赛季积分是如何生成的
首先赛季结束时我们将Redis中的历史数据持久化到数据库中的方式来保存赛季积分,如果用户量过大数据量就会过大,我们采用水平分表的放试来解决数据存储过多的问题,我们用到XXL-JOB设置定时任务当赛季初期会新建一张表,这张表就是保存的赛季积分信息。