面试题答案
一键面试资源竞争产生的原因
在多线程并发执行场景下,当多个线程同时访问和修改共享资源时,就会产生资源竞争。这是因为线程的执行是抢占式的,CPU 时间片在多个线程间快速切换,线程执行顺序不可预测。如果没有适当的同步机制,多个线程对共享资源的操作可能会相互干扰,导致数据不一致或程序出现错误。
常见解决资源竞争的方法
-
互斥锁(Mutex)
- 原理:互斥锁是一种二元信号量,它只有两种状态:锁定(locked)和未锁定(unlocked)。线程在访问共享资源前,必须先获取互斥锁。如果互斥锁已被其他线程锁定,那么当前线程会被阻塞,直到互斥锁被释放。只有获取到互斥锁的线程才能访问共享资源,访问完毕后释放互斥锁,让其他线程有机会获取并访问共享资源,以此保证同一时间只有一个线程能访问共享资源。
- 适用场景:适用于对共享资源访问频率较高,且访问时间较短的场景。例如,在多线程环境下对数据库连接池的访问,通过互斥锁可以保证每次只有一个线程从连接池中获取或归还连接,避免多个线程同时操作导致连接池状态混乱。
-
信号量(Semaphore)
- 原理:信号量维护了一个计数器,它允许一定数量的线程同时访问共享资源。线程在访问共享资源前需要获取信号量,如果信号量的计数器大于 0,则计数器减 1,线程可以继续执行;如果计数器为 0,线程会被阻塞,直到有其他线程释放信号量(计数器加 1)。通过设置信号量的初始计数值,可以控制同时访问共享资源的线程数量。
- 适用场景:适用于需要限制同时访问共享资源的线程数量的场景。比如,服务器端对某些资源的访问并发量有限制,通过信号量可以确保不超过这个限制。例如,一个服务器只能同时处理 10 个文件上传请求,就可以使用初始值为 10 的信号量来控制。
-
读写锁(Read - Write Lock)
- 原理:读写锁区分了读操作和写操作。允许多个线程同时进行读操作,因为读操作不会修改共享资源,不会产生数据竞争问题。而写操作会修改共享资源,为了保证数据一致性,当有线程进行写操作时,不允许其他线程进行读或写操作。写操作必须独占资源,直到写操作完成并释放锁。读锁可以被多个读线程同时获取,而写锁只能被一个写线程获取。
- 适用场景:适用于读操作远远多于写操作的场景。比如,在一个在线文档查看系统中,大量用户可能同时查看文档(读操作),但只有少数用户会进行编辑(写操作)。使用读写锁可以提高系统的并发性能,在读操作频繁的情况下,多个读线程可以并发执行,而写操作时则保证数据的一致性。