首先了解这两者是什么。

以下说明参考自python官网

Lock:Lock被称为①原始锁,原始锁是一个②在锁定时不属于特定线程的同步基元组件,它是能用的最低级的同步基元组件。原始锁处于 "锁定" 或者 "非锁定" 两种状态之一。它被创建时为非锁定状态。它有两个基本方法, acquire() 和 release() 。当状态为非锁定时, acquire() 将状态改为锁定并立即返回。当状态是锁定时, acquire() 将阻塞至其他线程调用 release() 将其改为非锁定状态,然后 acquire() 调用重置其为锁定状态并返回。 release() 只在锁定状态下调用; 它将状态改为非锁定并立即返回。如果尝试释放一个非锁定的锁,则会引发 RuntimeError  异常。锁支持 上下文管理协议,即支持with语句,下文例子中会用到。

RLock:RLock被称为重入锁,若要锁定锁,线程调用其 acquire() 方法;一旦线程拥有了锁,方法将返回。若要解锁,线程调用 release() 方法。 ③acquire()/release() 对可以嵌套,重入锁必须由获取它的线程释放。一旦线程获得了重入锁,同一个线程再次获取它将不阻塞。只有最终 release() (最外面一对的 release() ) 将锁解开,才能让其他线程继续处理 acquire() 阻塞。;线程必须在每次获取它时释放一次。

两者使用的方法大部分还是相同的,下面根据以上红色强调部分描述一下二者的区别

①是名称的区别,一个叫原始锁,一个叫重入锁,这没啥好说的

②Lock在锁定时不属于特定线程,也就是说,Lock可以在一个线程中上锁,在另一个线程中解锁。而对于RLock来说,只有当前线程才能释放本线程上的锁,即解铃还须系铃人:

import threading
import time lock = threading.Lock()
lock.acquire() def func():
lock.release()
print("lock is released") t = threading.Thread(target=func)
t.start() 输出结果为:lock is released

上面代码中,在主线程中创建锁,并上锁,但是是在t线程中释放锁,结果正常输出,说明一个线程上的锁,可以由另外线程解锁。如果把上面的锁改为RLock则报错

③也是这两者最大的区别了,RLock允许在同一线程中被多次acquire。而Lock却不允许这种情况。也就是说,下面的情况对于RLock是允许的:

import threading

rlock = threading.RLock()

def func():
if rlock.acquire(): # 第一把锁
print("first lock")
if rlock.acquire(): # 第一把锁没解开的情况下接着上第二把锁
print("second lock")
rlock.release() # 解开第二把锁
rlock.release() # 解开第一把锁 t = threading.Thread(target=func)
t.start() 输出结果:

first lock
   second lock

注意上面强调的同一线程中,因为对于RLock来说只有当前线程才能释放本线程上的锁,并不能在t1线程中已经执行rlock.acquire,且未释放锁的情况下,在另一个t2线程中还能执行rlock.acquire(这种情况会导致t2阻塞)

那么,既然一个线程可以通过Lock来获得一把锁,干嘛还要使用RLock去锁上加锁?考虑一下这种情况:

import threading
import time lock1 = threading.RLock() def inner():
with lock1:
print("inner1 function:%s" % threading.current_thread()) def outer():
print("outer function:%s" % threading.current_thread())
with lock1:
inner() if __name__ == "__main__":
t1 = threading.Thread(target=outer)
t2 = threading.Thread(target=outer)
t1.start()
t2.start()
结果:

  outer function:<Thread(Thread-1, started 12892)>
  inner1 function:<Thread(Thread-1, started 12892)>
  outer function:<Thread(Thread-2, started 7456)>
  inner1 function:<Thread(Thread-2, started 7456)>

首先只看t1线程,当执行到outer函数时,首先打印outer function:<Thread(Thread-1, started 12892)>,然后用lock1给当前线程上了一把锁,然后执行inner函数,在inner里面又需要用lock1来上一把锁,如果此时用Lock的话,由于已经上了一把锁,程序会因为第二次无法获得锁而导致t1阻塞,程序阻塞之后又没法释放锁,所以会导致程序死锁。这种情况下,RLock就派上用场了。t2线程执行过程和t1一样,这里只是多加个线程看起来酷炫一些

python threading模块的Lock和RLock区别的更多相关文章

  1. Python学习笔记- Python threading模块

    Python threading模块 直接调用 # !/usr/bin/env python # -*- coding:utf-8 -*- import threading import time d ...

  2. python threading模块使用 以及python多线程操作的实践(使用Queue队列模块)

    今天花了近乎一天的时间研究python关于多线程的问题,查看了大量源码 自己也实践了一个生产消费者模型,所以把一天的收获总结一下. 由于GIL(Global Interpreter Lock)锁的关系 ...

  3. python threading模块2

    Thread 是threading模块中最重要的类之一,可以使用它来创建线程.有两种方式来创建线程:一种是通过继承Thread类,重写它的run方法:另一种是创建一个threading.Thread对 ...

  4. Python——threading模块(线程)

    一.threading模块的对象 Thread:表示一个执行线程的对象 Lock:锁 Rlock:可重入锁对象 Condition:条件变量对象,使得一个线程等待另一个线程满足特定的“条件” Even ...

  5. python threading模块中对于信号的抓取

    最近的物联网智能网关(树莓派)项目中遇到这样一个问题:要从多个底层串口读取发来的数据,并且做出相应的处理,对于每个串口的数据的读取我能想到的可以采用两种方式: 一种是采用轮询串口的方式,例如每3s向每 ...

  6. python——threading模块

    一.什么是线程 线程是操作系统能够进行运算调度的最小单位.进程被包含在进程中,是进程中实际处理单位.一条线程就是一堆指令集合. 一条线程是指进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条 ...

  7. python threading 模块来实现多线程

    以多线程的方式向标准输出打印日志 #!/usr/bin/python import time import threading class PrintThread(threading.Thread): ...

  8. Python导入模块Import和from+Import区别

    在我们使用python的时候会发现使用Import可以导入模块,from+Import也可以,那么他们之间有什么区别,该用哪一种呢?让我们来看看 1.首先在demo.py中创建一个变量a,定义一个函数 ...

  9. python threading模块中的join()方法和setDeamon()方法的一些理解

    之前用多线程的时候看见了很多文章,比较常用的大概就是join()和setDeamon()了. 先说一下自己对join()的理解吧: def join(self, timeout=None): &quo ...

随机推荐

  1. 计蒜客 39270.Angel's Journey-简单的计算几何 ((The 2019 ACM-ICPC China Shannxi Provincial Programming Contest C.) 2019ICPC西安邀请赛现场赛重现赛

    Angel's Journey “Miyane!” This day Hana asks Miyako for help again. Hana plays the part of angel on ...

  2. GoCN每日新闻(2019-10-05)

     国庆专辑:GopherChina祝大家国庆节快乐GoCN每日新闻(2019-10-05) 1. Gophercon UK 2019 https://www.bilibili.com/video/av ...

  3. Java为什么没有指针

    为了摒弃指针带来的风险(当然了,也就放弃了指针带来的效率). 1.C/C++为什么有指针? 这个很简单,程序都是在内存中运行的,只要有内存,就有内存地址,有地址,就必然有指针,只是C++对内存地址的访 ...

  4. 富文本编辑器kindeditor的使用

    第一步:导入前端js文件 <!-- 富文本编辑器 --> <link rel="stylesheet" href="../plugins/kindedi ...

  5. springMVC开启声明式事务实现操作日志记录

    第一步.在applicationContext-mvc.xml开启AOP注解扫描 <aop:aspectj-autoproxy/> 第二步.创建增强类,实现日志记录 @Component ...

  6. 搭建Portainer可视化界面

    1.下载Portainer镜像 docker pull portainer/portainer 2.安装分为单机版及集群版 2.1单机版安装 docker run -d -p 9000:9000 \- ...

  7. Vue 自定义编译打包路径

    在 vue.config.js 文件下添加 outputDir 配置项: module.exports = { outputDir:"my_target_direct", // o ...

  8. [RoarCTF 2019]simple_uplod

    目录 [RoarCTF 2019]simple_uplod 1.ThinkPHP文件上传 2.upload()多文件上传 ThinkPHP上传文件名暴破 [RoarCTF 2019]simple_up ...

  9. 【转】使用eclipse的todo标签管理任务

    Eclipse中的一些特殊的注释技术包括:    1.    // TODO —— 表示尚未完成的待办事项.    2.    // XXX —— 表示被注释的代码虽然实现了功能,但是实现方案有待商榷 ...

  10. HIDL概述【转】

    本文转载自:https://blog.csdn.net/u013357557/article/details/84561457 HIDL背景Treble 是 Google Android 团队的一项重 ...