面试题答案
一键面试避免死锁的锁获取和释放机制设计
- 按顺序获取锁:所有线程都按照相同的顺序获取锁,这样可以避免循环等待导致的死锁。例如,假设有两个锁
lock1
和lock2
,所有线程都先获取lock1
,再获取lock2
。 - 使用
try - finally
块:在获取锁之后,无论是否发生异常,都要确保锁能正确释放。try - finally
块可以保证在try
块中的代码执行完毕后(无论是否发生异常),都会执行finally
块中的代码,从而释放锁。 - 设置锁的超时时间:在获取锁时设置一个超时时间,如果在超时时间内没有获取到锁,则放弃获取并进行相应处理,避免线程无限期等待。
代码示例
import threading
import time
# 创建两个锁
lock1 = threading.Lock()
lock2 = threading.Lock()
def thread_function():
# 按顺序获取锁
if lock1.acquire(timeout=1):
try:
print(f"{threading.current_thread().name} 获取了 lock1")
time.sleep(0.1)
if lock2.acquire(timeout=1):
try:
print(f"{threading.current_thread().name} 获取了 lock2")
# 这里访问和修改共享资源
time.sleep(0.1)
finally:
lock2.release()
print(f"{threading.current_thread().name} 释放了 lock2")
finally:
lock1.release()
print(f"{threading.current_thread().name} 释放了 lock1")
# 创建并启动多个线程
threads = []
for i in range(3):
t = threading.Thread(target=thread_function)
threads.append(t)
t.start()
# 等待所有线程完成
for t in threads:
t.join()
在上述代码中:
- 每个线程都尝试先获取
lock1
,设置超时时间为1秒,如果获取成功,在try
块中执行相关操作,最后在finally
块中释放lock1
。 - 在获取
lock1
成功后,再尝试获取lock2
,同样设置超时时间为1秒,获取成功后执行操作并在finally
块中释放lock2
。 - 通过这种方式,既保证了按顺序获取锁,又使用了超时机制和
try - finally
块确保锁的正确获取和释放,从而避免死锁。