[b0034] python 归纳 (十九)_线程同步_条件变量
代码:
# -*- coding: utf-8 -*- """ 学习线程同步,使用条件变量 逻辑: 生产消费者模型 一个有3个大小的产品库,一个生产者负责生产,一个消费者负责消费 每次生产或消费一个产品,产品库满了,生产者必须等待,产品库空了,消费者必须等待 生产者的速度是消费者的速度2倍,先启动消费者,一段时间后启动生产者 总结: 1. 条件变量底层用到R锁,对于已经获得锁的线程可以执行多次 acquire(),锁多次 2. 不确定是否和java的这一套 ,原理一样 使用: 1. 创建条件对象 cond = threading.Condition() 2. 在子线程调用 申请获取锁 cond.acquire() 3. 在程序中如果有必要 使用 cond.wait() cond.notify() cond.notifyall() 4. 使用完后 释放锁 cond.release() 参考: """ import threading import time class Goods: """ 记录产品数,最多3个产品 被多线程操作 """ def __init__(self): self.count = 0 def add(self,num = 1): self.count += num def sub(self): if self.count>=0: self.count -= 1 def empty(self): return self.count <= 0 def full(self): return self.count >= 3 class Producer(threading.Thread): """ 生产者 """ def __init__(self,condition,goods,name, sleeptime=1): threading.Thread.__init__(self) self.cond = condition self.goods = goods self.sleeptime = sleeptime self.name = name def run(self): cond = self.cond goods = self.goods while True: print "p1" cond.acquire() # 获取锁 print "p2" while goods.full(): # 如果产品满了 print "p3" cond.wait() print cond._Condition__lock print "p4" print "p5" goods.add() print("num:",goods.count,"producer") cond.notifyAll() # 唤醒所有等待的线程,并没有交出锁 print cond._Condition__lock # 锁还在 print "p6" cond.release() # 解锁资源 print cond._Condition__lock # 锁不在了 print "p7" time.sleep(self.sleeptime) class Consumer(threading.Thread): """ 消费者 """ def __init__(self,condition,goods,name, sleeptime=2): threading.Thread.__init__(self) self.cond = condition self.goods = goods self.sleeptime = sleeptime self.name = name def run(self): cond = self.cond goods = self.goods while True: print "c1" cond.acquire() # 获取锁 print "c2" while goods.empty(): # 如果没有产品了 print "c3" cond.wait() # 执行它,交出锁,进入等待池,然后阻塞,直到被唤醒 print cond._Condition__lock # 执行到这里,继续获得了锁 print "c4" print "c5" goods.sub() print("num:",goods.count, "consumer") cond.notifyAll() # 唤醒所有等待的线程,并没有交出锁 print cond._Condition__lock # 锁还在 print "c6" cond.release() # 解锁资源 print cond._Condition__lock # 锁不在了 print "c7" time.sleep(self.sleeptime) if __name__ == '__main__': g = Goods() # 共享数据 cond = threading.Condition() # 条件判断 # 启动消费者 consumer = Consumer(cond,g, name="consumer") consumer.start() # 2秒后启动生产者 time.sleep(2) print "m1" # 启动生产者 producer = Producer(cond,g, name="producer") producer.start() print "m2"
2 输出:
D:\Programs\Anaconda\python.exe D:/1_practice/python/projects/downloads_modify/归类/并发/thread_sync_5.py c1 c2 c3 m1 p1m2 p2 p5 ('num:', 1, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0><_RLock owner='consumer' count=1> p7c4 c5 ('num:', 0, 'consumer') <_RLock owner='consumer' count=1> c6 <_RLock owner=None count=0> c7 p1 p2 p5 ('num:', 1, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0> p7 p1 p2 p5 ('num:', 2, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0> p7 c1 c2 c5 ('num:', 1, 'consumer') <_RLock owner='consumer' count=1> c6 <_RLock owner=None count=0> c7 p1 p2 p5 ('num:', 2, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0> p7 p1 p2 p5 ('num:', 3, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0> p7 c1 c2 c5 ('num:', 2, 'consumer') <_RLock owner='consumer' count=1> c6 <_RLock owner=None count=0> c7 p1 p2 p5 ('num:', 3, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0> p7 p1 p2 p3 c1 c2 c5 ('num:', 2, 'consumer') <_RLock owner='consumer' count=1> c6 <_RLock owner=None count=0><_RLock owner='producer' count=1> c7p4 p5 ('num:', 3, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0> p7 p1 p2 p3 c1 c2 c5 ('num:', 2, 'consumer') <_RLock owner='consumer' count=1> c6 <_RLock owner=None count=0><_RLock owner='producer' count=1> c7p4 p5 ('num:', 3, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0> p7 p1 p2 p3 c1 c2 c5 ('num:', 2, 'consumer') <_RLock owner='consumer' count=1> c6 <_RLock owner='producer' count=1><_RLock owner=None count=1> p4c7 p5 ('num:', 3, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0> p7 p1 p2 p3 c1 c2 c5 ('num:', 2, 'consumer') <_RLock owner='consumer' count=1> c6 <_RLock owner=None count=0><_RLock owner='producer' count=1> c7p4 p5 ('num:', 3, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0> p7 p1 p2 p3 c1 c2 c5 ('num:', 2, 'consumer') <_RLock owner='consumer' count=1> c6 <_RLock owner=None count=0><_RLock owner='producer' count=1> c7p4 p5 ('num:', 3, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0> p7 p1 p2 p3 c1 c2 c5 ('num:', 2, 'consumer') <_RLock owner='consumer' count=1> c6 <_RLock owner=None count=0> c7<_RLock owner='producer' count=1> p4 p5 ('num:', 3, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0> p7 p1 p2 p3 c1 c2 c5 ('num:', 2, 'consumer') <_RLock owner='consumer' count=1> c6 <_RLock owner=None count=0><_RLock owner='producer' count=1> c7p4 p5 ('num:', 3, 'producer') <_RLock owner='producer' count=1> p6 <_RLock owner=None count=0> p7 Process finished with exit code -1
3 输出解读:
4 相关资料
java中的notify和notifyAll有什么区别?
先说两个概念:锁池和等待池
- 锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。
- 等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中
Reference:java中的锁池和等待池
链接:https://www.zhihu.com/question/37601861/answer/145545371
然后再来说notify和notifyAll的区别
- 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁。
- 当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
- 优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。
Reference:线程间协作:wait、notify、notifyAll
综上,所谓唤醒线程,另一种解释可以说是将线程由等待池移动到锁池,notifyAll调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify只会唤醒一个线程。
有了这些理论基础,后面的notify可能会导致死锁,而notifyAll则不会的例子也就好解释了
个人理解:
写满200篇博文再说