Python多线程Lock锁机制详解:从基础使用到死锁预防

Mia
Mia
发布时间:2026-10-12| 3人浏览过
原创

本文深入解析Python中threading.Lock的使用方式。通过对比未加锁与加锁的代码示例,展示线程执行顺序的控制方法。详细阐述线程不安全的原因,介绍Lock类的工作原理,并探讨RLock解决死锁问题的机制,帮助开发者掌握多线程编程中的资源同步技巧。

Python多线程中Lock锁(threading.Lock)的具体应用方法

核心疑问

多线程环境下任务默认并发执行,若需强制实现线程A先于线程B执行,应如何处理?

解决方案

引入Python的多线程锁机制(Lock)。

代码示例

未使用多线程锁Lock的情况:

def a():
    for i in range(3):
        print('a%d' % (i + 1))
        time.sleep(1)

def b():
    for i in range(3):
        print('b%d' % (i + 1))
        time.sleep(1)

T = threading.Thread(target=a)
T.start()

T = threading.Thread(target=b)
T.start()

运行结果分析:可见线程A与线程B交替执行,并未按顺序完成。

a1 b1 a2b2

a3 b3

Process finished with exit code 0

使用多线程锁Lock后的情况:

lock = threading.Lock()

def a():
    lock.acquire()
    for i in range(3):
        print('a%d' % (i + 1))
        time.sleep(1)
    lock.release()

def b():
    lock.acquire()
    for i in range(3):
        print('b%d' % (i + 1))
        time.sleep(1)
    lock.release()

T = threading.Thread(target=a)
T.start()

T = threading.Thread(target=b)
T.start()

运行结果分析:可见线程A完整执行完毕后,线程B才开始执行。

a1 a2 a3 b1 b2 b3

Process finished with exit code 0

Python多线程中锁的核心概念

锁对象可独立定义与提取

mutex = threading.Lock()
#锁的使用
#创建锁
mutex = threading.Lock()
#锁定
mutex.acquire([timeout])
#释放
mutex.release()

概念解析

关于资源加锁的常见误解:并非直接给资源加锁,而是通过锁对象来锁定资源。开发者可以定义多个锁对象,当需要独占某一资源时,任意一个锁均可用于锁定该资源。

这类似于使用不同类型的钥匙都能打开同一把门锁的原理。

import  threading   
import  time   
counter = 0 
counter_lock = threading.Lock() #只是定义一个锁,并不是给资源加锁,你可以定义多个锁,像下两行代码,当你需要占用这个资源时,任何一个锁都可以锁这个资源 
counter_lock2 = threading.Lock()  
counter_lock3 = threading.Lock() 
   
#可以使用上边三个锁的任何一个来锁定资源 
    
class  MyThread(threading.Thread):#使用类定义thread,继承threading.Thread 
     def  __init__(self,name):   
        threading.Thread.__init__(self)   
        self.name = "Thread-" + str(name) 
     def run(self):   #run函数必须实现 
         global counter,counter_lock #多线程是共享资源的,使用全局变量 
         time.sleep(1);   
         if counter_lock.acquire(): #当需要独占counter资源时,必须先锁定,这个锁可以是任意的一个锁,可以使用上边定义的3个锁中的任意一个 
            counter += 1    
            print "I am %s, set counter:%s"  % (self.name,counter)   
            counter_lock.release() #使用完counter资源必须要将这个锁打开,让其他线程使用 
               
if  __name__ ==  "__main__":   
    for i in xrange(1,101):   
        my_thread = MyThread(i) 
        my_thread.start()

线程不安全现象

考察一个基础的多线程示例。代码创建了一个继承自Thread类的子类MyThread作为线程启动类,并重写了run方法,线程启动后自动调用该方法。示例中创建了10个线程并加入列表,通过for循环依次启动各线程,最后再次使用for循环调用join方法,确保所有线程结束后主线程才退出。

该代码表面简单,实则隐含严重问题。虽然逻辑上按顺序创建了10个线程并期望每个线程为变量n增加1,但实际执行中,可能是线程A执行n++后,线程C执行n++,接着线程B执行n++。

这涉及“锁”的概念。若多个线程同时操作同一对象且缺乏保护,会导致程序结果不可预期(例如在run方法中加入time.sleep(1)并输出线程名,会发现输出杂乱无章,因为print语句可能只输出一半字符时线程被挂起,转而执行其他线程)。这种现象被称为“线程不安全”。

线程锁机制

Threading模块提供了Threading.Lock类作为解决方案。通过创建该对象,在线程函数执行前“抢占”该锁,执行完成后“释放”该锁,可确保同一时刻仅有一个线程持有该锁。此时对公共对象进行操作,即可避免线程不安全现象。

修改后的代码如下:

# coding : uft-8
__author__ = 'Phtih0n'
import threading, time
class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        global n, lock
        time.sleep(1)
        if lock.acquire():
            print n , self.name
            n += 1
            lock.release()
if "__main__" == __name__:
    n = 1
    ThreadList = []
    lock = threading.Lock()
    for i in range(1, 200):
        t = MyThread()
        ThreadList.append(t)
    for t in ThreadList:
        t.start()
    for t in ThreadList:
        t.join()

1 Thread-2 2 Thread-3 3 Thread-4 4 Thread-6 5 Thread-7 6 Thread-1 7 Thread-8 8 Thread-9 9 Thread-5 Process finished with exit code 0

代码首先建立了threading.Lock类对象lock。在run方法中,使用lock.acquire()获取锁。此时其他线程无法获得该锁,将阻塞在“if lock.acquire()”处,直到当前线程通过lock.release()释放锁。

因此,if语句包裹的代码块成为完整执行单元,不再出现执行一半被挂起去执行其他线程的情况,最终结果整齐有序。

这类似于Java中使用synchronized关键字修饰方法,目的相同:确保某段代码被一个线程执行时,不会中断并跳转到另一个线程。

上述情况适用于多线程占用单个公共对象。若多个线程调用多个对象,且线程A通过A锁占用对象A,线程B通过B锁占用对象B,而线程A试图调用对象B、线程B试图调用对象A,双方将无限等待,导致“死锁”。

Threading模块提供了RLock类,即可重入锁。该锁内部维护一个Lock对象和一个counter计数器。counter记录acquire的次数,允许资源被多次请求。只有当所有RLock被release后,其他线程才能获取资源。在同一个线程中,RLock.acquire可被多次调用,利用此特性可解决部分死锁问题。

以上为个人经验分享,旨在提供参考,感谢大家的支持。

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。