面试题答案
一键面试设计思路
- 使用无锁数据结构:例如,采用原子操作的计数器。在现代多核处理器架构下,原子操作可以直接在硬件层面保证操作的原子性,无需额外的锁机制。这能大大减少锁争用带来的性能损耗。
- 减少共享状态:尽量将计数器操作分散,避免所有线程都直接对同一个全局计数器进行操作。可以考虑每个线程先维护自己的局部计数器,在合适的时机将局部计数器的值合并到全局计数器上。这样能减少对全局计数器的争用。
- 读写分离策略:对于读操作远多于写操作的场景,可以采用读写锁。读操作可以并行执行,只有写操作需要独占锁,从而提高并发性能。但要注意读写锁的使用场景,如果写操作过于频繁,可能导致读操作长时间等待。
关键技术点
- 原子操作:不同编程语言都提供了原子操作的支持,如 C++ 的
<atomic>
库,Java 的java.util.concurrent.atomic
包。以 C++ 为例,std::atomic<int>
类型的变量可以进行原子的增减操作,如atomic_var.fetch_add(1)
,这些操作在硬件层面保证原子性,无需额外锁。 - 线程局部存储(TLS):许多编程语言提供了线程局部存储机制,如 C++ 的
thread_local
关键字,Java 的ThreadLocal
类。利用这个机制,每个线程可以有自己独立的计数器实例。例如,在 C++ 中定义thread_local int local_counter = 0;
,线程对local_counter
的操作不会产生竞争。在需要统计全局结果时,将所有线程的local_counter
值合并到全局计数器上。 - 读写锁实现:在 C++ 中,可以使用
std::shared_mutex
实现读写锁。读操作时使用std::shared_lock<std::shared_mutex>
来获取共享锁,允许多个读操作并行;写操作时使用std::unique_lock<std::shared_mutex>
来获取独占锁。在 Java 中,可以使用ReentrantReadWriteLock
实现类似功能。读操作调用lockRead()
方法,写操作调用lockWrite()
方法。