面试题答案
一键面试底层数据结构优化
- 替换为分段数组:
- 优化方式:将原来单一的哈希表结构,改为多个子哈希表(分段数组)的形式。例如,Java中的
ConcurrentHashMap
在JDK1.7及之前版本就是采用这种结构。每个子哈希表都有独立的锁。 - 提升性能原因:不同子哈希表可以同时进行读写操作,锁竞争大大降低。当多个线程访问不同子哈希表时,不会相互阻塞,提高了并发度。
- 优化方式:将原来单一的哈希表结构,改为多个子哈希表(分段数组)的形式。例如,Java中的
- 使用跳表等数据结构:
- 优化方式:跳表是一种可以在$O(\log n)$时间复杂度内完成查找、插入和删除操作的数据结构。可以在高并发场景下,将哈希表的桶(bucket)结构替换为跳表。
- 提升性能原因:跳表的有序性和分层结构使得在高并发读写时,锁的粒度可以更细。比如在查找操作时,不同线程可以在跳表的不同层次并行查找,减少锁冲突,提高性能。
锁粒度优化
- 减小锁粒度:
- 优化方式:从对整个哈希表加锁,改为对哈希表中的每个桶(bucket)加锁。例如,在
ConcurrentHashMap
的JDK1.8版本中,就使用了CAS(Compare - and - Swap)操作和同步块synchronized
结合的方式,对链表或红黑树节点所在的桶加锁。 - 提升性能原因:多个线程可以同时访问不同的桶,只有在访问同一个桶时才会竞争锁,相比对整个哈希表加锁,锁冲突的概率大幅降低,从而提升并发性能。
- 优化方式:从对整个哈希表加锁,改为对哈希表中的每个桶(bucket)加锁。例如,在
- 读写锁分离:
- 优化方式:使用读写锁(ReadWriteLock),读操作可以共享锁,写操作独占锁。例如在一些哈希表实现中,读操作获取读锁,写操作获取写锁。
- 提升性能原因:在高并发读多写少的场景下,多个读操作可以同时进行,不会相互阻塞,只有写操作会与读操作或其他写操作竞争锁,提高了系统的并发读性能。
缓存一致性优化
- 使用本地缓存:
- 优化方式:在每个线程本地维护一个缓存,线程优先从本地缓存中读取数据。只有当本地缓存中没有所需数据时,才去访问共享的哈希表。
- 提升性能原因:减少了对共享哈希表的读请求次数,降低了锁竞争。同时,由于本地缓存访问速度快,整体性能得到提升。
- 采用写后更新策略:
- 优化方式:写操作先在本地缓存进行标记,等某个合适的时机(如批量写操作完成、系统空闲时)再更新到共享哈希表。
- 提升性能原因:减少了写操作对共享哈希表的频繁更新,降低了锁竞争,从而提升了高并发场景下的性能。