ZetCode

Python 锁

最后修改:2025 年 2 月 15 日

在本文中,我们将展示如何使用 threading.Lock 同步 Python 线程。

Lock 是一种同步原语,可确保一次只有一个线程可以访问共享资源。它对于防止多个线程尝试同时修改共享数据时出现的竞态条件非常有用。

Lock 有两种状态:锁定和未锁定。线程可以使用 acquire 方法获取锁,并使用 release 方法释放锁。如果锁已被另一个线程获取,则调用线程将阻塞,直到锁被释放。

锁示例

以下示例演示了如何使用 threading.Lock 来保护共享资源。

main.py
import threading

class SharedResource:
    def __init__(self):
        self.lock = threading.Lock()
        self.value = 0

    def increment(self):
        with self.lock:  # Acquire and release the lock automatically
            self.value += 1
            print(f"Value after increment: {self.value}")

def worker(shared_resource):
    for _ in range(5):  # Each thread increments the value 5 times
        shared_resource.increment()

def main():
    shared_resource = SharedResource()

    threads = []
    for i in range(3):  # Create 3 threads
        thread = threading.Thread(target=worker, args=(shared_resource,))
        threads.append(thread)
        thread.start()

    for thread in threads:
        thread.join()  # Wait for all threads to complete

    print(f"Final value: {shared_resource.value}")

if __name__ == "__main__":
    main()

在此程序中,使用 Lock 来保护共享的整数值。多个线程递增该值,并且锁确保一次只有一个线程可以修改该值。

self.lock = threading.Lock()

SharedResource 类使用 Lock 初始化,以保护共享值。

with self.lock:  # Acquire and release the lock automatically

with 语句用于自动获取和释放锁,从而确保适当的同步。

shared_resource = SharedResource()

初始化 SharedResource,并使用锁来保护共享值。

$ python main.py
Value after increment: 1
Value after increment: 2
Value after increment: 3
Value after increment: 4
Value after increment: 5
Value after increment: 6
Value after increment: 7
Value after increment: 8
Value after increment: 9
Value after increment: 10
Value after increment: 11
Value after increment: 12
Value after increment: 13
Value after increment: 14
Value after increment: 15
Final value: 15

带超时的锁

以下示例演示了如何使用带超时的 Lock。如果线程无法在指定的超时时间内获取锁,它将继续执行而不修改共享资源。

main.py
import threading
import time

class SharedResource:
    def __init__(self):
        self.lock = threading.Lock()
        self.value = 0

    def increment(self):
        if self.lock.acquire(timeout=1):  # Try to acquire the lock with a timeout
            try:
                self.value += 1
                print(f"Value after increment: {self.value}")
            finally:
                self.lock.release()  # Release the lock
        else:
            print("Could not acquire the lock")

def worker(shared_resource):
    for _ in range(5):  # Each thread increments the value 5 times
        shared_resource.increment()
        time.sleep(0.5)  # Simulate some work

def main():
    shared_resource = SharedResource()

    threads = []
    for i in range(3):  # Create 3 threads
        thread = threading.Thread(target=worker, args=(shared_resource,))
        threads.append(thread)
        thread.start()

    for thread in threads:
        thread.join()  # Wait for all threads to complete

    print(f"Final value: {shared_resource.value}")

if __name__ == "__main__":
    main()

在此程序中,Lock 与超时一起使用。如果线程无法在 1 秒内获取锁,它将继续执行而不修改共享资源。

if self.lock.acquire(timeout=1):  # Try to acquire the lock with a timeout

acquire 方法被调用,超时时间为 1 秒。如果在此时间内未获取锁,则线程将继续执行而不修改共享资源。

$ python main.py
Value after increment: 1
Value after increment: 2
Value after increment: 3
Value after increment: 4
Value after increment: 5
Value after increment: 6
Value after increment: 7
Value after increment: 8
Value after increment: 9
Value after increment: 10
Value after increment: 11
Value after increment: 12
Value after increment: 13
Value after increment: 14
Value after increment: 15
Final value: 15

带锁的线程安全队列示例

以下示例演示了如何使用 threading.Lock 来实现线程安全队列。锁确保一次只有一个线程可以修改队列。

main.py
import threading
import time
import queue

class ThreadSafeQueue:
    def __init__(self):
        self.queue = queue.Queue()
        self.lock = threading.Lock()

    def put(self, item):
        with self.lock:  # Acquire and release the lock automatically
            self.queue.put(item)
            print(f"Added item: {item}")

    def get(self):
        with self.lock:  # Acquire and release the lock automatically
            if not self.queue.empty():
                item = self.queue.get()
                print(f"Removed item: {item}")
                return item
            return None

def producer(safe_queue):
    for i in range(5):  # Produce 5 items
        safe_queue.put(i)
        time.sleep(0.5)  # Simulate production time

def consumer(safe_queue):
    for _ in range(5):  # Consume 5 items
        safe_queue.get()
        time.sleep(1)  # Simulate consumption time

def main():
    safe_queue = ThreadSafeQueue()

    # Create producer and consumer threads
    producer_thread = threading.Thread(target=producer, args=(safe_queue,))
    consumer_thread = threading.Thread(target=consumer, args=(safe_queue,))

    producer_thread.start()
    consumer_thread.start()

    producer_thread.join()
    consumer_thread.join()

    print("Queue operations completed")

if __name__ == "__main__":
    main()

在此程序中,使用 Lock 来保护共享队列。生产者线程将项目添加到队列,而消费者线程从队列中删除项目。锁确保一次只有一个线程可以修改队列。

self.lock = threading.Lock()

ThreadSafeQueue 类使用 Lock 初始化,以保护共享队列。

with self.lock:  # Acquire and release the lock automatically

with 语句用于自动获取和释放锁,从而确保适当的同步。

safe_queue = ThreadSafeQueue()

初始化 ThreadSafeQueue,并使用锁来保护共享队列。

$ python main.py
Added item: 0
Removed item: 0
Added item: 1
Added item: 2
Removed item: 1
Added item: 3
Added item: 4
Removed item: 2
Removed item: 3
Removed item: 4
Queue operations completed

来源

Python 锁 - 文档

在本文中,我们展示了如何使用 Lock 同步 Python 线程以进行资源管理。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。到目前为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出所有 Python 教程