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

Python中线程未持有锁为何能释放?有序打印代码锁疑问

LeetCode有序打印问题的锁同步疑惑解答

问题背景

我在解决LeetCode的有序打印问题时,用Lock做线程同步,代码能正常运行,但有个疑惑:

代码实现

from threading import Lock, current_thread
from concurrent import futures
from typing import Callable

class Foo:
    def __init__(self):
        self.first_lock = Lock()
        self.second_lock = Lock()
        self.first_lock.acquire()
        self.second_lock.acquire()
        print(f'{current_thread()} in __init__')

    def first(self, printFirst: Callable[[], None]) -> None:
        print(f'{current_thread()} in first')
        printFirst()
        self.first_lock.release()


    def second(self, printSecond: Callable[[], None]) -> None:
        print(f'{current_thread()} in second')
        with self.first_lock:
            printSecond()
            self.second_lock.release()


    def third(self, printThird: Callable[[], None]) -> None:
        print(f'{current_thread()} in third')
        with self.second_lock:
            printThird()

def printFirst():
    print("First")

def printSecond():
    print("Second")

def printThird():
    print("Third")

foo = Foo()
with futures.ThreadPoolExecutor(max_workers=3) as executor:
    to_do: list[futures.Future] = []
    to_do.append(executor.submit(foo.third, printThird))
    to_do.append(executor.submit(foo.second, printSecond))
    to_do.append(executor.submit(foo.first, printFirst))
    
print("all set?")

疑问

foo在主线程中实例化,所以主线程持有这两个锁?如果是这样,主线程从未释放锁,为什么执行first方法的其他线程可以释放该锁?


解答

核心原因是:Python标准库的threading.Lock不与特定线程绑定。

具体说明:

  • threading.Lock只关注自身的状态(锁定/未锁定),不校验调用release()的线程是否是之前调用acquire()的线程。只要当前锁处于锁定状态,任何线程调用release()都能将其解锁;只有当锁已经处于未锁定状态时调用release(),才会抛出RuntimeError。
  • 回到你的代码逻辑:
    1. 主线程在Foo初始化时,通过acquire()将first_lock和second_lock置为锁定状态。
    2. 线程池中的first线程执行self.first_lock.release(),直接解锁first_lock,无需考虑锁的持有者是主线程。
    3. 解锁后second线程的with self.first_lock能成功获取锁,执行完打印逻辑后调用self.second_lock.release()解锁第二个锁,最后third线程通过with self.second_lock获取锁完成执行。

需要注意:这种跨线程释放锁的写法属于利用Python Lock的实现特性,不符合锁的常规使用规范(通常要求获取锁的线程负责释放锁)。更规范的实现可以用threading.Event或threading.Condition来明确控制执行顺序,逻辑会更清晰,也更符合多线程同步的最佳实践。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 04:21:48