面试题答案
一键面试优化互斥锁性能的方法
- 减少锁的粒度 原理:将大的临界区细分为多个小的临界区,每个小临界区使用单独的锁。这样不同线程可以同时访问不同的小临界区,提高并发度。例如在一个包含多个数据项的对象中,为每个数据项或相关的数据子集设置单独的锁,而不是对整个对象加一把大锁。
- 使用读写锁 原理:读写锁区分了读操作和写操作。多个线程可以同时进行读操作,因为读操作不会修改共享资源,不会产生数据不一致问题。只有写操作时才需要独占锁,以保证数据的一致性。这样在读多写少的场景下,可以显著提高并发性能。
- 锁的分层与分段 原理:类似于减少锁粒度,将系统中的数据按照一定规则进行分层或分段,每层或每段使用单独的锁。比如在数据库中,可以按照表、行等不同层次设置锁,使得不同线程可以在不同层次上并行操作,减少锁竞争。
- 采用乐观锁 原理:乐观锁假设在大多数情况下,并发操作不会发生冲突。在更新数据时,先检查数据是否被其他线程修改。如果没有被修改,则进行更新;如果已被修改,则重试操作。乐观锁通常通过版本号或时间戳机制实现,适用于冲突较少的场景,避免了传统互斥锁带来的线程阻塞开销。
预防死锁的方法
- 破坏死锁的四个必要条件
- 破坏互斥条件:在某些情况下,使资源不具有互斥性。但这在实际应用中较难实现,因为很多资源本身就具有互斥特性,如打印机。
- 破坏占有并等待条件:要求线程一次性申请所有需要的资源,而不是逐步申请。这样就不会出现一个线程占有部分资源,又等待其他资源的情况。例如,一个线程需要资源A和B,它必须同时申请A和B,若其中一个资源不可用,则不占用任何资源,避免死锁。
- 破坏不可剥夺条件:允许系统剥夺已经分配给某个线程的资源。当一个线程占有资源但又无法获取其他所需资源时,系统可以剥夺其已占有的资源,分配给其他需要的线程,从而打破死锁。不过,这需要系统具备相应的资源管理和调度机制。
- 破坏循环等待条件:对资源进行排序,规定线程必须按照一定顺序申请资源。例如,给所有资源编号,线程只能按照编号从小到大的顺序申请资源,这样就不会形成循环等待链,从而预防死锁。
- 使用死锁检测与恢复机制 原理:系统定期检测是否存在死锁。检测方法通常是通过资源分配图算法,分析线程和资源之间的依赖关系,判断是否存在死锁环。一旦检测到死锁,系统可以选择终止一个或多个线程,释放它们占用的资源,从而解除死锁。但这种方法成本较高,因为终止线程可能导致任务中断,需要合理选择终止的线程,并在事后进行恢复操作。