You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python多线程锁跨线程释放代码逻辑的两大疑问

关于Python threading.Lock的两个疑问解答

先看你提供的代码:

import threading
import time

shared = 0
lock = threading.Lock()

def funcA():
    global shared
    for i in range(10):
        time.sleep(1)
        shared += 10
        print(f"Thread A wrote: {shared}")
        lock.acquire()

def funcB():
    global shared
    lock.acquire()
    for i in range(10):
        time.sleep(1)
        shared -= 10
        print(f"Thread B wrote: {shared}")
        lock.release()

t1 = threading.Thread(target=funcA)
t2 = threading.Thread(target=funcB)
t1.start()
t2.start()
t1.join()
t2.join()

疑问1:funcA每次循环获取锁但未释放,为何没有报错?

threading.Lock是不可重入锁,它的规则是:同一线程只能获取锁一次,重复调用acquire()不会抛出异常,而是会让当前线程进入阻塞状态(自己死锁自己)。

在funcA的执行流程里:

  • 第一次循环:执行完print后调用lock.acquire(),成功拿到锁。
  • 第二次循环:执行到lock.acquire()时,因为当前线程已经持有这个锁,而Lock不允许同一线程重复获取,所以funcA会卡在这一步,不再继续执行后续循环,但不会抛出任何错误——你看到的“没报错”其实是线程阻塞了,程序并没有正常完成所有10次循环。

疑问2:funcA始终未释放锁,为何funcB能正常再次获取锁?

这是线程启动顺序导致的随机结果:

  • 如果t2.start()后,funcB先执行了lock.acquire(),成功拿到锁,那么funcB会进入循环,每次循环末尾调用lock.release()释放锁。这时候funcA里的lock.acquire()会一直等待,直到funcB释放锁才能获取。
  • 反过来,如果funcA先拿到锁,那么funcB的lock.acquire()会一直阻塞,永远无法进入循环。

另外要注意:这段代码是错误的锁用法,threading.Lock的设计原则是谁获取谁释放,跨线程释放锁属于未定义行为,虽然Python不会直接报错,但会导致锁状态混乱,完全不符合线程安全的设计初衷。

内容的提问来源于stack exchange,提问作者Richard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 14:28:27